• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 %                                                                             %
4 %                                                                             %
5 %                                                                             %
6 %                                 FFFFF  X   X                                %
7 %                                 F       X X                                 %
8 %                                 FFF      X                                  %
9 %                                 F       X X                                 %
10 %                                 F      X   X                                %
11 %                                                                             %
12 %                                                                             %
13 %                   MagickCore Image Special Effects Methods                  %
14 %                                                                             %
15 %                               Software Design                               %
16 %                                    Cristy                                   %
17 %                                 October 1996                                %
18 %                                                                             %
19 %                                                                             %
20 %                                                                             %
21 %  Copyright 1999-2020 ImageMagick Studio LLC, a non-profit organization      %
22 %  dedicated to making software imaging solutions freely available.           %
23 %                                                                             %
24 %  You may not use this file except in compliance with the License.  You may  %
25 %  obtain a copy of the License at                                            %
26 %                                                                             %
27 %    https://imagemagick.org/script/license.php                               %
28 %                                                                             %
29 %  Unless required by applicable law or agreed to in writing, software        %
30 %  distributed under the License is distributed on an "AS IS" BASIS,          %
31 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
32 %  See the License for the specific language governing permissions and        %
33 %  limitations under the License.                                             %
34 %                                                                             %
35 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
36 %
37 %
38 %
39 */
40 
41 /*
42   Include declarations.
43 */
44 #include "MagickCore/studio.h"
45 #include "MagickCore/accelerate-private.h"
46 #include "MagickCore/annotate.h"
47 #include "MagickCore/artifact.h"
48 #include "MagickCore/attribute.h"
49 #include "MagickCore/cache.h"
50 #include "MagickCore/cache-view.h"
51 #include "MagickCore/channel.h"
52 #include "MagickCore/color.h"
53 #include "MagickCore/color-private.h"
54 #include "MagickCore/colorspace-private.h"
55 #include "MagickCore/composite.h"
56 #include "MagickCore/decorate.h"
57 #include "MagickCore/distort.h"
58 #include "MagickCore/draw.h"
59 #include "MagickCore/effect.h"
60 #include "MagickCore/enhance.h"
61 #include "MagickCore/exception.h"
62 #include "MagickCore/exception-private.h"
63 #include "MagickCore/gem.h"
64 #include "MagickCore/gem-private.h"
65 #include "MagickCore/geometry.h"
66 #include "MagickCore/layer.h"
67 #include "MagickCore/list.h"
68 #include "MagickCore/log.h"
69 #include "MagickCore/image.h"
70 #include "MagickCore/image-private.h"
71 #include "MagickCore/magick.h"
72 #include "MagickCore/memory_.h"
73 #include "MagickCore/memory-private.h"
74 #include "MagickCore/monitor.h"
75 #include "MagickCore/monitor-private.h"
76 #include "MagickCore/option.h"
77 #include "MagickCore/pixel.h"
78 #include "MagickCore/pixel-accessor.h"
79 #include "MagickCore/property.h"
80 #include "MagickCore/quantum.h"
81 #include "MagickCore/quantum-private.h"
82 #include "MagickCore/random_.h"
83 #include "MagickCore/random-private.h"
84 #include "MagickCore/resample.h"
85 #include "MagickCore/resample-private.h"
86 #include "MagickCore/resize.h"
87 #include "MagickCore/resource_.h"
88 #include "MagickCore/splay-tree.h"
89 #include "MagickCore/statistic.h"
90 #include "MagickCore/string_.h"
91 #include "MagickCore/string-private.h"
92 #include "MagickCore/thread-private.h"
93 #include "MagickCore/threshold.h"
94 #include "MagickCore/transform.h"
95 #include "MagickCore/transform-private.h"
96 #include "MagickCore/utility.h"
97 #include "MagickCore/visual-effects.h"
98 
99 /*
100 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
101 %                                                                             %
102 %                                                                             %
103 %                                                                             %
104 %     A d d N o i s e I m a g e                                               %
105 %                                                                             %
106 %                                                                             %
107 %                                                                             %
108 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
109 %
110 %  AddNoiseImage() adds random noise to the image.
111 %
112 %  The format of the AddNoiseImage method is:
113 %
114 %      Image *AddNoiseImage(const Image *image,const NoiseType noise_type,
115 %        const double attenuate,ExceptionInfo *exception)
116 %
117 %  A description of each parameter follows:
118 %
119 %    o image: the image.
120 %
121 %    o channel: the channel type.
122 %
123 %    o noise_type:  The type of noise: Uniform, Gaussian, Multiplicative,
124 %      Impulse, Laplacian, or Poisson.
125 %
126 %    o attenuate:  attenuate the random distribution.
127 %
128 %    o exception: return any errors or warnings in this structure.
129 %
130 */
AddNoiseImage(const Image * image,const NoiseType noise_type,const double attenuate,ExceptionInfo * exception)131 MagickExport Image *AddNoiseImage(const Image *image,const NoiseType noise_type,
132   const double attenuate,ExceptionInfo *exception)
133 {
134 #define AddNoiseImageTag  "AddNoise/Image"
135 
136   CacheView
137     *image_view,
138     *noise_view;
139 
140   Image
141     *noise_image;
142 
143   MagickBooleanType
144     status;
145 
146   MagickOffsetType
147     progress;
148 
149   RandomInfo
150     **magick_restrict random_info;
151 
152   ssize_t
153     y;
154 
155 #if defined(MAGICKCORE_OPENMP_SUPPORT)
156   unsigned long
157     key;
158 #endif
159 
160   /*
161     Initialize noise image attributes.
162   */
163   assert(image != (const Image *) NULL);
164   assert(image->signature == MagickCoreSignature);
165   if (image->debug != MagickFalse)
166     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
167   assert(exception != (ExceptionInfo *) NULL);
168   assert(exception->signature == MagickCoreSignature);
169 #if defined(MAGICKCORE_OPENCL_SUPPORT)
170   noise_image=AccelerateAddNoiseImage(image,noise_type,attenuate,exception);
171   if (noise_image != (Image *) NULL)
172     return(noise_image);
173 #endif
174   noise_image=CloneImage(image,0,0,MagickTrue,exception);
175   if (noise_image == (Image *) NULL)
176     return((Image *) NULL);
177   if (SetImageStorageClass(noise_image,DirectClass,exception) == MagickFalse)
178     {
179       noise_image=DestroyImage(noise_image);
180       return((Image *) NULL);
181     }
182   /*
183     Add noise in each row.
184   */
185   status=MagickTrue;
186   progress=0;
187   random_info=AcquireRandomInfoThreadSet();
188   image_view=AcquireVirtualCacheView(image,exception);
189   noise_view=AcquireAuthenticCacheView(noise_image,exception);
190 #if defined(MAGICKCORE_OPENMP_SUPPORT)
191   key=GetRandomSecretKey(random_info[0]);
192   #pragma omp parallel for schedule(static) shared(progress,status) \
193     magick_number_threads(image,noise_image,image->rows,key == ~0UL)
194 #endif
195   for (y=0; y < (ssize_t) image->rows; y++)
196   {
197     const int
198       id = GetOpenMPThreadId();
199 
200     MagickBooleanType
201       sync;
202 
203     register const Quantum
204       *magick_restrict p;
205 
206     register ssize_t
207       x;
208 
209     register Quantum
210       *magick_restrict q;
211 
212     if (status == MagickFalse)
213       continue;
214     p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
215     q=QueueCacheViewAuthenticPixels(noise_view,0,y,noise_image->columns,1,
216       exception);
217     if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
218       {
219         status=MagickFalse;
220         continue;
221       }
222     for (x=0; x < (ssize_t) image->columns; x++)
223     {
224       register ssize_t
225         i;
226 
227       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
228       {
229         PixelChannel channel = GetPixelChannelChannel(image,i);
230         PixelTrait traits = GetPixelChannelTraits(image,channel);
231         PixelTrait noise_traits=GetPixelChannelTraits(noise_image,channel);
232         if ((traits == UndefinedPixelTrait) ||
233             (noise_traits == UndefinedPixelTrait))
234           continue;
235         if ((noise_traits & CopyPixelTrait) != 0)
236           {
237             SetPixelChannel(noise_image,channel,p[i],q);
238             continue;
239           }
240         SetPixelChannel(noise_image,channel,ClampToQuantum(
241           GenerateDifferentialNoise(random_info[id],p[i],noise_type,attenuate)),
242           q);
243       }
244       p+=GetPixelChannels(image);
245       q+=GetPixelChannels(noise_image);
246     }
247     sync=SyncCacheViewAuthenticPixels(noise_view,exception);
248     if (sync == MagickFalse)
249       status=MagickFalse;
250     if (image->progress_monitor != (MagickProgressMonitor) NULL)
251       {
252         MagickBooleanType
253           proceed;
254 
255 #if defined(MAGICKCORE_OPENMP_SUPPORT)
256         #pragma omp atomic
257 #endif
258         progress++;
259         proceed=SetImageProgress(image,AddNoiseImageTag,progress,image->rows);
260         if (proceed == MagickFalse)
261           status=MagickFalse;
262       }
263   }
264   noise_view=DestroyCacheView(noise_view);
265   image_view=DestroyCacheView(image_view);
266   random_info=DestroyRandomInfoThreadSet(random_info);
267   if (status == MagickFalse)
268     noise_image=DestroyImage(noise_image);
269   return(noise_image);
270 }
271 
272 /*
273 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
274 %                                                                             %
275 %                                                                             %
276 %                                                                             %
277 %     B l u e S h i f t I m a g e                                             %
278 %                                                                             %
279 %                                                                             %
280 %                                                                             %
281 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
282 %
283 %  BlueShiftImage() mutes the colors of the image to simulate a scene at
284 %  nighttime in the moonlight.
285 %
286 %  The format of the BlueShiftImage method is:
287 %
288 %      Image *BlueShiftImage(const Image *image,const double factor,
289 %        ExceptionInfo *exception)
290 %
291 %  A description of each parameter follows:
292 %
293 %    o image: the image.
294 %
295 %    o factor: the shift factor.
296 %
297 %    o exception: return any errors or warnings in this structure.
298 %
299 */
BlueShiftImage(const Image * image,const double factor,ExceptionInfo * exception)300 MagickExport Image *BlueShiftImage(const Image *image,const double factor,
301   ExceptionInfo *exception)
302 {
303 #define BlueShiftImageTag  "BlueShift/Image"
304 
305   CacheView
306     *image_view,
307     *shift_view;
308 
309   Image
310     *shift_image;
311 
312   MagickBooleanType
313     status;
314 
315   MagickOffsetType
316     progress;
317 
318   ssize_t
319     y;
320 
321   /*
322     Allocate blue shift image.
323   */
324   assert(image != (const Image *) NULL);
325   assert(image->signature == MagickCoreSignature);
326   if (image->debug != MagickFalse)
327     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
328   assert(exception != (ExceptionInfo *) NULL);
329   assert(exception->signature == MagickCoreSignature);
330   shift_image=CloneImage(image,0,0,MagickTrue,exception);
331   if (shift_image == (Image *) NULL)
332     return((Image *) NULL);
333   if (SetImageStorageClass(shift_image,DirectClass,exception) == MagickFalse)
334     {
335       shift_image=DestroyImage(shift_image);
336       return((Image *) NULL);
337     }
338   /*
339     Blue-shift DirectClass image.
340   */
341   status=MagickTrue;
342   progress=0;
343   image_view=AcquireVirtualCacheView(image,exception);
344   shift_view=AcquireAuthenticCacheView(shift_image,exception);
345 #if defined(MAGICKCORE_OPENMP_SUPPORT)
346   #pragma omp parallel for schedule(static) shared(progress,status) \
347     magick_number_threads(image,shift_image,image->rows,1)
348 #endif
349   for (y=0; y < (ssize_t) image->rows; y++)
350   {
351     MagickBooleanType
352       sync;
353 
354     PixelInfo
355       pixel;
356 
357     Quantum
358       quantum;
359 
360     register const Quantum
361       *magick_restrict p;
362 
363     register ssize_t
364       x;
365 
366     register Quantum
367       *magick_restrict q;
368 
369     if (status == MagickFalse)
370       continue;
371     p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
372     q=QueueCacheViewAuthenticPixels(shift_view,0,y,shift_image->columns,1,
373       exception);
374     if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
375       {
376         status=MagickFalse;
377         continue;
378       }
379     for (x=0; x < (ssize_t) image->columns; x++)
380     {
381       quantum=GetPixelRed(image,p);
382       if (GetPixelGreen(image,p) < quantum)
383         quantum=GetPixelGreen(image,p);
384       if (GetPixelBlue(image,p) < quantum)
385         quantum=GetPixelBlue(image,p);
386       pixel.red=0.5*(GetPixelRed(image,p)+factor*quantum);
387       pixel.green=0.5*(GetPixelGreen(image,p)+factor*quantum);
388       pixel.blue=0.5*(GetPixelBlue(image,p)+factor*quantum);
389       quantum=GetPixelRed(image,p);
390       if (GetPixelGreen(image,p) > quantum)
391         quantum=GetPixelGreen(image,p);
392       if (GetPixelBlue(image,p) > quantum)
393         quantum=GetPixelBlue(image,p);
394       pixel.red=0.5*(pixel.red+factor*quantum);
395       pixel.green=0.5*(pixel.green+factor*quantum);
396       pixel.blue=0.5*(pixel.blue+factor*quantum);
397       SetPixelRed(shift_image,ClampToQuantum(pixel.red),q);
398       SetPixelGreen(shift_image,ClampToQuantum(pixel.green),q);
399       SetPixelBlue(shift_image,ClampToQuantum(pixel.blue),q);
400       p+=GetPixelChannels(image);
401       q+=GetPixelChannels(shift_image);
402     }
403     sync=SyncCacheViewAuthenticPixels(shift_view,exception);
404     if (sync == MagickFalse)
405       status=MagickFalse;
406     if (image->progress_monitor != (MagickProgressMonitor) NULL)
407       {
408         MagickBooleanType
409           proceed;
410 
411 #if defined(MAGICKCORE_OPENMP_SUPPORT)
412         #pragma omp atomic
413 #endif
414         progress++;
415         proceed=SetImageProgress(image,BlueShiftImageTag,progress,image->rows);
416         if (proceed == MagickFalse)
417           status=MagickFalse;
418       }
419   }
420   image_view=DestroyCacheView(image_view);
421   shift_view=DestroyCacheView(shift_view);
422   if (status == MagickFalse)
423     shift_image=DestroyImage(shift_image);
424   return(shift_image);
425 }
426 
427 /*
428 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
429 %                                                                             %
430 %                                                                             %
431 %                                                                             %
432 %     C h a r c o a l I m a g e                                               %
433 %                                                                             %
434 %                                                                             %
435 %                                                                             %
436 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
437 %
438 %  CharcoalImage() creates a new image that is a copy of an existing one with
439 %  the edge highlighted.  It allocates the memory necessary for the new Image
440 %  structure and returns a pointer to the new image.
441 %
442 %  The format of the CharcoalImage method is:
443 %
444 %      Image *CharcoalImage(const Image *image,const double radius,
445 %        const double sigma,ExceptionInfo *exception)
446 %
447 %  A description of each parameter follows:
448 %
449 %    o image: the image.
450 %
451 %    o radius: the radius of the pixel neighborhood.
452 %
453 %    o sigma: the standard deviation of the Gaussian, in pixels.
454 %
455 %    o exception: return any errors or warnings in this structure.
456 %
457 */
CharcoalImage(const Image * image,const double radius,const double sigma,ExceptionInfo * exception)458 MagickExport Image *CharcoalImage(const Image *image,const double radius,
459   const double sigma,ExceptionInfo *exception)
460 {
461   Image
462     *charcoal_image,
463     *edge_image;
464 
465   MagickBooleanType
466     status;
467 
468   assert(image != (Image *) NULL);
469   assert(image->signature == MagickCoreSignature);
470   if (image->debug != MagickFalse)
471     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
472   assert(exception != (ExceptionInfo *) NULL);
473   assert(exception->signature == MagickCoreSignature);
474   edge_image=EdgeImage(image,radius,exception);
475   if (edge_image == (Image *) NULL)
476     return((Image *) NULL);
477   charcoal_image=(Image *) NULL;
478   status=ClampImage(edge_image,exception);
479   if (status != MagickFalse)
480     charcoal_image=BlurImage(edge_image,radius,sigma,exception);
481   edge_image=DestroyImage(edge_image);
482   if (charcoal_image == (Image *) NULL)
483     return((Image *) NULL);
484   status=NormalizeImage(charcoal_image,exception);
485   if (status != MagickFalse)
486     status=NegateImage(charcoal_image,MagickFalse,exception);
487   if (status != MagickFalse)
488     status=GrayscaleImage(charcoal_image,image->intensity,exception);
489   if (status == MagickFalse)
490     charcoal_image=DestroyImage(charcoal_image);
491   return(charcoal_image);
492 }
493 
494 /*
495 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
496 %                                                                             %
497 %                                                                             %
498 %                                                                             %
499 %     C o l o r i z e I m a g e                                               %
500 %                                                                             %
501 %                                                                             %
502 %                                                                             %
503 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
504 %
505 %  ColorizeImage() blends the fill color with each pixel in the image.
506 %  A percentage blend is specified with opacity.  Control the application
507 %  of different color components by specifying a different percentage for
508 %  each component (e.g. 90/100/10 is 90% red, 100% green, and 10% blue).
509 %
510 %  The format of the ColorizeImage method is:
511 %
512 %      Image *ColorizeImage(const Image *image,const char *blend,
513 %        const PixelInfo *colorize,ExceptionInfo *exception)
514 %
515 %  A description of each parameter follows:
516 %
517 %    o image: the image.
518 %
519 %    o blend:  A character string indicating the level of blending as a
520 %      percentage.
521 %
522 %    o colorize: A color value.
523 %
524 %    o exception: return any errors or warnings in this structure.
525 %
526 */
ColorizeImage(const Image * image,const char * blend,const PixelInfo * colorize,ExceptionInfo * exception)527 MagickExport Image *ColorizeImage(const Image *image,const char *blend,
528   const PixelInfo *colorize,ExceptionInfo *exception)
529 {
530 #define ColorizeImageTag  "Colorize/Image"
531 #define Colorize(pixel,blend_percentage,colorize)  \
532   (((pixel)*(100.0-(blend_percentage))+(colorize)*(blend_percentage))/100.0)
533 
534   CacheView
535     *image_view;
536 
537   GeometryInfo
538     geometry_info;
539 
540   Image
541     *colorize_image;
542 
543   MagickBooleanType
544     status;
545 
546   MagickOffsetType
547     progress;
548 
549   MagickStatusType
550     flags;
551 
552   PixelInfo
553     blend_percentage;
554 
555   ssize_t
556     y;
557 
558   /*
559     Allocate colorized image.
560   */
561   assert(image != (const Image *) NULL);
562   assert(image->signature == MagickCoreSignature);
563   if (image->debug != MagickFalse)
564     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
565   assert(exception != (ExceptionInfo *) NULL);
566   assert(exception->signature == MagickCoreSignature);
567   colorize_image=CloneImage(image,0,0,MagickTrue,exception);
568   if (colorize_image == (Image *) NULL)
569     return((Image *) NULL);
570   if (SetImageStorageClass(colorize_image,DirectClass,exception) == MagickFalse)
571     {
572       colorize_image=DestroyImage(colorize_image);
573       return((Image *) NULL);
574     }
575   if ((IsGrayColorspace(colorize_image->colorspace) != MagickFalse) ||
576       (IsPixelInfoGray(colorize) != MagickFalse))
577     (void) SetImageColorspace(colorize_image,sRGBColorspace,exception);
578   if ((colorize_image->alpha_trait == UndefinedPixelTrait) &&
579       (colorize->alpha_trait != UndefinedPixelTrait))
580     (void) SetImageAlpha(colorize_image,OpaqueAlpha,exception);
581   if (blend == (const char *) NULL)
582     return(colorize_image);
583   GetPixelInfo(colorize_image,&blend_percentage);
584   flags=ParseGeometry(blend,&geometry_info);
585   blend_percentage.red=geometry_info.rho;
586   blend_percentage.green=geometry_info.rho;
587   blend_percentage.blue=geometry_info.rho;
588   blend_percentage.black=geometry_info.rho;
589   blend_percentage.alpha=(MagickRealType) TransparentAlpha;
590   if ((flags & SigmaValue) != 0)
591     blend_percentage.green=geometry_info.sigma;
592   if ((flags & XiValue) != 0)
593     blend_percentage.blue=geometry_info.xi;
594   if ((flags & PsiValue) != 0)
595     blend_percentage.alpha=geometry_info.psi;
596   if (blend_percentage.colorspace == CMYKColorspace)
597     {
598       if ((flags & PsiValue) != 0)
599         blend_percentage.black=geometry_info.psi;
600       if ((flags & ChiValue) != 0)
601         blend_percentage.alpha=geometry_info.chi;
602     }
603   /*
604     Colorize DirectClass image.
605   */
606   status=MagickTrue;
607   progress=0;
608   image_view=AcquireVirtualCacheView(colorize_image,exception);
609 #if defined(MAGICKCORE_OPENMP_SUPPORT)
610   #pragma omp parallel for schedule(static) shared(progress,status) \
611     magick_number_threads(colorize_image,colorize_image,colorize_image->rows,1)
612 #endif
613   for (y=0; y < (ssize_t) colorize_image->rows; y++)
614   {
615     MagickBooleanType
616       sync;
617 
618     register Quantum
619       *magick_restrict q;
620 
621     register ssize_t
622       x;
623 
624     if (status == MagickFalse)
625       continue;
626     q=GetCacheViewAuthenticPixels(image_view,0,y,colorize_image->columns,1,
627       exception);
628     if (q == (Quantum *) NULL)
629       {
630         status=MagickFalse;
631         continue;
632       }
633     for (x=0; x < (ssize_t) colorize_image->columns; x++)
634     {
635       register ssize_t
636         i;
637 
638       for (i=0; i < (ssize_t) GetPixelChannels(colorize_image); i++)
639       {
640         PixelTrait traits = GetPixelChannelTraits(colorize_image,
641           (PixelChannel) i);
642         if (traits == UndefinedPixelTrait)
643           continue;
644         if ((traits & CopyPixelTrait) != 0)
645           continue;
646         SetPixelChannel(colorize_image,(PixelChannel) i,ClampToQuantum(
647           Colorize(q[i],GetPixelInfoChannel(&blend_percentage,(PixelChannel) i),
648           GetPixelInfoChannel(colorize,(PixelChannel) i))),q);
649       }
650       q+=GetPixelChannels(colorize_image);
651     }
652     sync=SyncCacheViewAuthenticPixels(image_view,exception);
653     if (sync == MagickFalse)
654       status=MagickFalse;
655     if (image->progress_monitor != (MagickProgressMonitor) NULL)
656       {
657         MagickBooleanType
658           proceed;
659 
660 #if defined(MAGICKCORE_OPENMP_SUPPORT)
661         #pragma omp atomic
662 #endif
663         progress++;
664         proceed=SetImageProgress(image,ColorizeImageTag,progress,
665           colorize_image->rows);
666         if (proceed == MagickFalse)
667           status=MagickFalse;
668       }
669   }
670   image_view=DestroyCacheView(image_view);
671   if (status == MagickFalse)
672     colorize_image=DestroyImage(colorize_image);
673   return(colorize_image);
674 }
675 
676 /*
677 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
678 %                                                                             %
679 %                                                                             %
680 %                                                                             %
681 %     C o l o r M a t r i x I m a g e                                         %
682 %                                                                             %
683 %                                                                             %
684 %                                                                             %
685 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
686 %
687 %  ColorMatrixImage() applies color transformation to an image. This method
688 %  permits saturation changes, hue rotation, luminance to alpha, and various
689 %  other effects.  Although variable-sized transformation matrices can be used,
690 %  typically one uses a 5x5 matrix for an RGBA image and a 6x6 for CMYKA
691 %  (or RGBA with offsets).  The matrix is similar to those used by Adobe Flash
692 %  except offsets are in column 6 rather than 5 (in support of CMYKA images)
693 %  and offsets are normalized (divide Flash offset by 255).
694 %
695 %  The format of the ColorMatrixImage method is:
696 %
697 %      Image *ColorMatrixImage(const Image *image,
698 %        const KernelInfo *color_matrix,ExceptionInfo *exception)
699 %
700 %  A description of each parameter follows:
701 %
702 %    o image: the image.
703 %
704 %    o color_matrix:  the color matrix.
705 %
706 %    o exception: return any errors or warnings in this structure.
707 %
708 */
709 /* FUTURE: modify to make use of a MagickMatrix Mutliply function
710    That should be provided in "matrix.c"
711    (ASIDE: actually distorts should do this too but currently doesn't)
712 */
713 
ColorMatrixImage(const Image * image,const KernelInfo * color_matrix,ExceptionInfo * exception)714 MagickExport Image *ColorMatrixImage(const Image *image,
715   const KernelInfo *color_matrix,ExceptionInfo *exception)
716 {
717 #define ColorMatrixImageTag  "ColorMatrix/Image"
718 
719   CacheView
720     *color_view,
721     *image_view;
722 
723   double
724     ColorMatrix[6][6] =
725     {
726       { 1.0, 0.0, 0.0, 0.0, 0.0, 0.0 },
727       { 0.0, 1.0, 0.0, 0.0, 0.0, 0.0 },
728       { 0.0, 0.0, 1.0, 0.0, 0.0, 0.0 },
729       { 0.0, 0.0, 0.0, 1.0, 0.0, 0.0 },
730       { 0.0, 0.0, 0.0, 0.0, 1.0, 0.0 },
731       { 0.0, 0.0, 0.0, 0.0, 0.0, 1.0 }
732     };
733 
734   Image
735     *color_image;
736 
737   MagickBooleanType
738     status;
739 
740   MagickOffsetType
741     progress;
742 
743   register ssize_t
744     i;
745 
746   ssize_t
747     u,
748     v,
749     y;
750 
751   /*
752     Map given color_matrix, into a 6x6 matrix   RGBKA and a constant
753   */
754   assert(image != (Image *) NULL);
755   assert(image->signature == MagickCoreSignature);
756   if (image->debug != MagickFalse)
757     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
758   assert(exception != (ExceptionInfo *) NULL);
759   assert(exception->signature == MagickCoreSignature);
760   i=0;
761   for (v=0; v < (ssize_t) color_matrix->height; v++)
762     for (u=0; u < (ssize_t) color_matrix->width; u++)
763     {
764       if ((v < 6) && (u < 6))
765         ColorMatrix[v][u]=color_matrix->values[i];
766       i++;
767     }
768   /*
769     Initialize color image.
770   */
771   color_image=CloneImage(image,0,0,MagickTrue,exception);
772   if (color_image == (Image *) NULL)
773     return((Image *) NULL);
774   if (SetImageStorageClass(color_image,DirectClass,exception) == MagickFalse)
775     {
776       color_image=DestroyImage(color_image);
777       return((Image *) NULL);
778     }
779   if (image->debug != MagickFalse)
780     {
781       char
782         format[MagickPathExtent],
783         *message;
784 
785       (void) LogMagickEvent(TransformEvent,GetMagickModule(),
786         "  ColorMatrix image with color matrix:");
787       message=AcquireString("");
788       for (v=0; v < 6; v++)
789       {
790         *message='\0';
791         (void) FormatLocaleString(format,MagickPathExtent,"%.20g: ",(double) v);
792         (void) ConcatenateString(&message,format);
793         for (u=0; u < 6; u++)
794         {
795           (void) FormatLocaleString(format,MagickPathExtent,"%+f ",
796             ColorMatrix[v][u]);
797           (void) ConcatenateString(&message,format);
798         }
799         (void) LogMagickEvent(TransformEvent,GetMagickModule(),"%s",message);
800       }
801       message=DestroyString(message);
802     }
803   /*
804     Apply the ColorMatrix to image.
805   */
806   status=MagickTrue;
807   progress=0;
808   image_view=AcquireVirtualCacheView(image,exception);
809   color_view=AcquireAuthenticCacheView(color_image,exception);
810 #if defined(MAGICKCORE_OPENMP_SUPPORT)
811   #pragma omp parallel for schedule(static) shared(progress,status) \
812     magick_number_threads(image,color_image,image->rows,1)
813 #endif
814   for (y=0; y < (ssize_t) image->rows; y++)
815   {
816     PixelInfo
817       pixel;
818 
819     register const Quantum
820       *magick_restrict p;
821 
822     register Quantum
823       *magick_restrict q;
824 
825     register ssize_t
826       x;
827 
828     if (status == MagickFalse)
829       continue;
830     p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
831     q=GetCacheViewAuthenticPixels(color_view,0,y,color_image->columns,1,
832       exception);
833     if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
834       {
835         status=MagickFalse;
836         continue;
837       }
838     GetPixelInfo(image,&pixel);
839     for (x=0; x < (ssize_t) image->columns; x++)
840     {
841       register ssize_t
842         v;
843 
844       size_t
845         height;
846 
847       GetPixelInfoPixel(image,p,&pixel);
848       height=color_matrix->height > 6 ? 6UL : color_matrix->height;
849       for (v=0; v < (ssize_t) height; v++)
850       {
851         double
852           sum;
853 
854         sum=ColorMatrix[v][0]*GetPixelRed(image,p)+ColorMatrix[v][1]*
855           GetPixelGreen(image,p)+ColorMatrix[v][2]*GetPixelBlue(image,p);
856         if (image->colorspace == CMYKColorspace)
857           sum+=ColorMatrix[v][3]*GetPixelBlack(image,p);
858         if (image->alpha_trait != UndefinedPixelTrait)
859           sum+=ColorMatrix[v][4]*GetPixelAlpha(image,p);
860         sum+=QuantumRange*ColorMatrix[v][5];
861         switch (v)
862         {
863           case 0: pixel.red=sum; break;
864           case 1: pixel.green=sum; break;
865           case 2: pixel.blue=sum; break;
866           case 3: pixel.black=sum; break;
867           case 4: pixel.alpha=sum; break;
868           default: break;
869         }
870       }
871       SetPixelViaPixelInfo(color_image,&pixel,q);
872       p+=GetPixelChannels(image);
873       q+=GetPixelChannels(color_image);
874     }
875     if (SyncCacheViewAuthenticPixels(color_view,exception) == MagickFalse)
876       status=MagickFalse;
877     if (image->progress_monitor != (MagickProgressMonitor) NULL)
878       {
879         MagickBooleanType
880           proceed;
881 
882 #if defined(MAGICKCORE_OPENMP_SUPPORT)
883         #pragma omp atomic
884 #endif
885         progress++;
886         proceed=SetImageProgress(image,ColorMatrixImageTag,progress,
887           image->rows);
888         if (proceed == MagickFalse)
889           status=MagickFalse;
890       }
891   }
892   color_view=DestroyCacheView(color_view);
893   image_view=DestroyCacheView(image_view);
894   if (status == MagickFalse)
895     color_image=DestroyImage(color_image);
896   return(color_image);
897 }
898 
899 /*
900 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
901 %                                                                             %
902 %                                                                             %
903 %                                                                             %
904 %     I m p l o d e I m a g e                                                 %
905 %                                                                             %
906 %                                                                             %
907 %                                                                             %
908 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
909 %
910 %  ImplodeImage() creates a new image that is a copy of an existing
911 %  one with the image pixels "implode" by the specified percentage.  It
912 %  allocates the memory necessary for the new Image structure and returns a
913 %  pointer to the new image.
914 %
915 %  The format of the ImplodeImage method is:
916 %
917 %      Image *ImplodeImage(const Image *image,const double amount,
918 %        const PixelInterpolateMethod method,ExceptionInfo *exception)
919 %
920 %  A description of each parameter follows:
921 %
922 %    o implode_image: Method ImplodeImage returns a pointer to the image
923 %      after it is implode.  A null image is returned if there is a memory
924 %      shortage.
925 %
926 %    o image: the image.
927 %
928 %    o amount:  Define the extent of the implosion.
929 %
930 %    o method: the pixel interpolation method.
931 %
932 %    o exception: return any errors or warnings in this structure.
933 %
934 */
ImplodeImage(const Image * image,const double amount,const PixelInterpolateMethod method,ExceptionInfo * exception)935 MagickExport Image *ImplodeImage(const Image *image,const double amount,
936   const PixelInterpolateMethod method,ExceptionInfo *exception)
937 {
938 #define ImplodeImageTag  "Implode/Image"
939 
940   CacheView
941     *canvas_view,
942     *implode_view,
943     *interpolate_view;
944 
945   double
946     radius;
947 
948   Image
949     *canvas_image,
950     *implode_image;
951 
952   MagickBooleanType
953     status;
954 
955   MagickOffsetType
956     progress;
957 
958   PointInfo
959     center,
960     scale;
961 
962   ssize_t
963     y;
964 
965   /*
966     Initialize implode image attributes.
967   */
968   assert(image != (Image *) NULL);
969   assert(image->signature == MagickCoreSignature);
970   if (image->debug != MagickFalse)
971     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
972   assert(exception != (ExceptionInfo *) NULL);
973   assert(exception->signature == MagickCoreSignature);
974   canvas_image=CloneImage(image,0,0,MagickTrue,exception);
975   if (canvas_image == (Image *) NULL)
976     return((Image *) NULL);
977   if ((canvas_image->alpha_trait == UndefinedPixelTrait) &&
978       (canvas_image->background_color.alpha != OpaqueAlpha))
979     (void) SetImageAlphaChannel(canvas_image,OpaqueAlphaChannel,exception);
980   implode_image=CloneImage(canvas_image,0,0,MagickTrue,exception);
981   if (implode_image == (Image *) NULL)
982     {
983       canvas_image=DestroyImage(canvas_image);
984       return((Image *) NULL);
985     }
986   if (SetImageStorageClass(implode_image,DirectClass,exception) == MagickFalse)
987     {
988       canvas_image=DestroyImage(canvas_image);
989       implode_image=DestroyImage(implode_image);
990       return((Image *) NULL);
991     }
992   /*
993     Compute scaling factor.
994   */
995   scale.x=1.0;
996   scale.y=1.0;
997   center.x=0.5*canvas_image->columns;
998   center.y=0.5*canvas_image->rows;
999   radius=center.x;
1000   if (canvas_image->columns > canvas_image->rows)
1001     scale.y=(double) canvas_image->columns/(double) canvas_image->rows;
1002   else
1003     if (canvas_image->columns < canvas_image->rows)
1004       {
1005         scale.x=(double) canvas_image->rows/(double) canvas_image->columns;
1006         radius=center.y;
1007       }
1008   /*
1009     Implode image.
1010   */
1011   status=MagickTrue;
1012   progress=0;
1013   canvas_view=AcquireVirtualCacheView(canvas_image,exception);
1014   interpolate_view=AcquireVirtualCacheView(canvas_image,exception);
1015   implode_view=AcquireAuthenticCacheView(implode_image,exception);
1016 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1017   #pragma omp parallel for schedule(static) shared(progress,status) \
1018     magick_number_threads(canvas_image,implode_image,canvas_image->rows,1)
1019 #endif
1020   for (y=0; y < (ssize_t) canvas_image->rows; y++)
1021   {
1022     double
1023       distance;
1024 
1025     PointInfo
1026       delta;
1027 
1028     register const Quantum
1029       *magick_restrict p;
1030 
1031     register ssize_t
1032       x;
1033 
1034     register Quantum
1035       *magick_restrict q;
1036 
1037     if (status == MagickFalse)
1038       continue;
1039     p=GetCacheViewVirtualPixels(canvas_view,0,y,canvas_image->columns,1,
1040       exception);
1041     q=QueueCacheViewAuthenticPixels(implode_view,0,y,implode_image->columns,1,
1042       exception);
1043     if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
1044       {
1045         status=MagickFalse;
1046         continue;
1047       }
1048     delta.y=scale.y*(double) (y-center.y);
1049     for (x=0; x < (ssize_t) canvas_image->columns; x++)
1050     {
1051       register ssize_t
1052         i;
1053 
1054       /*
1055         Determine if the pixel is within an ellipse.
1056       */
1057       delta.x=scale.x*(double) (x-center.x);
1058       distance=delta.x*delta.x+delta.y*delta.y;
1059       if (distance >= (radius*radius))
1060         for (i=0; i < (ssize_t) GetPixelChannels(canvas_image); i++)
1061         {
1062           PixelChannel channel = GetPixelChannelChannel(canvas_image,i);
1063           PixelTrait traits = GetPixelChannelTraits(canvas_image,channel);
1064           PixelTrait implode_traits = GetPixelChannelTraits(implode_image,
1065             channel);
1066           if ((traits == UndefinedPixelTrait) ||
1067               (implode_traits == UndefinedPixelTrait))
1068             continue;
1069           SetPixelChannel(implode_image,channel,p[i],q);
1070         }
1071       else
1072         {
1073           double
1074             factor;
1075 
1076           /*
1077             Implode the pixel.
1078           */
1079           factor=1.0;
1080           if (distance > 0.0)
1081             factor=pow(sin(MagickPI*sqrt((double) distance)/radius/2),-amount);
1082           status=InterpolatePixelChannels(canvas_image,interpolate_view,
1083             implode_image,method,(double) (factor*delta.x/scale.x+center.x),
1084             (double) (factor*delta.y/scale.y+center.y),q,exception);
1085           if (status == MagickFalse)
1086             break;
1087         }
1088       p+=GetPixelChannels(canvas_image);
1089       q+=GetPixelChannels(implode_image);
1090     }
1091     if (SyncCacheViewAuthenticPixels(implode_view,exception) == MagickFalse)
1092       status=MagickFalse;
1093     if (canvas_image->progress_monitor != (MagickProgressMonitor) NULL)
1094       {
1095         MagickBooleanType
1096           proceed;
1097 
1098 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1099         #pragma omp atomic
1100 #endif
1101         progress++;
1102         proceed=SetImageProgress(canvas_image,ImplodeImageTag,progress,
1103           canvas_image->rows);
1104         if (proceed == MagickFalse)
1105           status=MagickFalse;
1106       }
1107   }
1108   implode_view=DestroyCacheView(implode_view);
1109   interpolate_view=DestroyCacheView(interpolate_view);
1110   canvas_view=DestroyCacheView(canvas_view);
1111   canvas_image=DestroyImage(canvas_image);
1112   if (status == MagickFalse)
1113     implode_image=DestroyImage(implode_image);
1114   return(implode_image);
1115 }
1116 
1117 /*
1118 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1119 %                                                                             %
1120 %                                                                             %
1121 %                                                                             %
1122 %     M o r p h I m a g e s                                                   %
1123 %                                                                             %
1124 %                                                                             %
1125 %                                                                             %
1126 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1127 %
1128 %  The MorphImages() method requires a minimum of two images.  The first
1129 %  image is transformed into the second by a number of intervening images
1130 %  as specified by frames.
1131 %
1132 %  The format of the MorphImage method is:
1133 %
1134 %      Image *MorphImages(const Image *image,const size_t number_frames,
1135 %        ExceptionInfo *exception)
1136 %
1137 %  A description of each parameter follows:
1138 %
1139 %    o image: the image.
1140 %
1141 %    o number_frames:  Define the number of in-between image to generate.
1142 %      The more in-between frames, the smoother the morph.
1143 %
1144 %    o exception: return any errors or warnings in this structure.
1145 %
1146 */
MorphImages(const Image * image,const size_t number_frames,ExceptionInfo * exception)1147 MagickExport Image *MorphImages(const Image *image,const size_t number_frames,
1148   ExceptionInfo *exception)
1149 {
1150 #define MorphImageTag  "Morph/Image"
1151 
1152   double
1153     alpha,
1154     beta;
1155 
1156   Image
1157     *morph_image,
1158     *morph_images;
1159 
1160   MagickBooleanType
1161     status;
1162 
1163   MagickOffsetType
1164     scene;
1165 
1166   register const Image
1167     *next;
1168 
1169   register ssize_t
1170     n;
1171 
1172   ssize_t
1173     y;
1174 
1175   /*
1176     Clone first frame in sequence.
1177   */
1178   assert(image != (Image *) NULL);
1179   assert(image->signature == MagickCoreSignature);
1180   if (image->debug != MagickFalse)
1181     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1182   assert(exception != (ExceptionInfo *) NULL);
1183   assert(exception->signature == MagickCoreSignature);
1184   morph_images=CloneImage(image,0,0,MagickTrue,exception);
1185   if (morph_images == (Image *) NULL)
1186     return((Image *) NULL);
1187   if (GetNextImageInList(image) == (Image *) NULL)
1188     {
1189       /*
1190         Morph single image.
1191       */
1192       for (n=1; n < (ssize_t) number_frames; n++)
1193       {
1194         morph_image=CloneImage(image,0,0,MagickTrue,exception);
1195         if (morph_image == (Image *) NULL)
1196           {
1197             morph_images=DestroyImageList(morph_images);
1198             return((Image *) NULL);
1199           }
1200         AppendImageToList(&morph_images,morph_image);
1201         if (image->progress_monitor != (MagickProgressMonitor) NULL)
1202           {
1203             MagickBooleanType
1204               proceed;
1205 
1206             proceed=SetImageProgress(image,MorphImageTag,(MagickOffsetType) n,
1207               number_frames);
1208             if (proceed == MagickFalse)
1209               status=MagickFalse;
1210           }
1211       }
1212       return(GetFirstImageInList(morph_images));
1213     }
1214   /*
1215     Morph image sequence.
1216   */
1217   status=MagickTrue;
1218   scene=0;
1219   next=image;
1220   for ( ; GetNextImageInList(next) != (Image *) NULL; next=GetNextImageInList(next))
1221   {
1222     for (n=0; n < (ssize_t) number_frames; n++)
1223     {
1224       CacheView
1225         *image_view,
1226         *morph_view;
1227 
1228       beta=(double) (n+1.0)/(double) (number_frames+1.0);
1229       alpha=1.0-beta;
1230       morph_image=ResizeImage(next,(size_t) (alpha*next->columns+beta*
1231         GetNextImageInList(next)->columns+0.5),(size_t) (alpha*next->rows+beta*
1232         GetNextImageInList(next)->rows+0.5),next->filter,exception);
1233       if (morph_image == (Image *) NULL)
1234         {
1235           morph_images=DestroyImageList(morph_images);
1236           return((Image *) NULL);
1237         }
1238       status=SetImageStorageClass(morph_image,DirectClass,exception);
1239       if (status == MagickFalse)
1240         {
1241           morph_image=DestroyImage(morph_image);
1242           return((Image *) NULL);
1243         }
1244       AppendImageToList(&morph_images,morph_image);
1245       morph_images=GetLastImageInList(morph_images);
1246       morph_image=ResizeImage(GetNextImageInList(next),morph_images->columns,
1247         morph_images->rows,GetNextImageInList(next)->filter,exception);
1248       if (morph_image == (Image *) NULL)
1249         {
1250           morph_images=DestroyImageList(morph_images);
1251           return((Image *) NULL);
1252         }
1253       image_view=AcquireVirtualCacheView(morph_image,exception);
1254       morph_view=AcquireAuthenticCacheView(morph_images,exception);
1255 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1256       #pragma omp parallel for schedule(static) shared(status) \
1257         magick_number_threads(morph_image,morph_image,morph_image->rows,1)
1258 #endif
1259       for (y=0; y < (ssize_t) morph_images->rows; y++)
1260       {
1261         MagickBooleanType
1262           sync;
1263 
1264         register const Quantum
1265           *magick_restrict p;
1266 
1267         register ssize_t
1268           x;
1269 
1270         register Quantum
1271           *magick_restrict q;
1272 
1273         if (status == MagickFalse)
1274           continue;
1275         p=GetCacheViewVirtualPixels(image_view,0,y,morph_image->columns,1,
1276           exception);
1277         q=GetCacheViewAuthenticPixels(morph_view,0,y,morph_images->columns,1,
1278           exception);
1279         if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
1280           {
1281             status=MagickFalse;
1282             continue;
1283           }
1284         for (x=0; x < (ssize_t) morph_images->columns; x++)
1285         {
1286           register ssize_t
1287             i;
1288 
1289           for (i=0; i < (ssize_t) GetPixelChannels(morph_image); i++)
1290           {
1291             PixelChannel channel = GetPixelChannelChannel(morph_image,i);
1292             PixelTrait traits = GetPixelChannelTraits(morph_image,channel);
1293             PixelTrait morph_traits=GetPixelChannelTraits(morph_images,channel);
1294             if ((traits == UndefinedPixelTrait) ||
1295                 (morph_traits == UndefinedPixelTrait))
1296               continue;
1297             if ((morph_traits & CopyPixelTrait) != 0)
1298               {
1299                 SetPixelChannel(morph_image,channel,p[i],q);
1300                 continue;
1301               }
1302             SetPixelChannel(morph_image,channel,ClampToQuantum(alpha*
1303               GetPixelChannel(morph_images,channel,q)+beta*p[i]),q);
1304           }
1305           p+=GetPixelChannels(morph_image);
1306           q+=GetPixelChannels(morph_images);
1307         }
1308         sync=SyncCacheViewAuthenticPixels(morph_view,exception);
1309         if (sync == MagickFalse)
1310           status=MagickFalse;
1311       }
1312       morph_view=DestroyCacheView(morph_view);
1313       image_view=DestroyCacheView(image_view);
1314       morph_image=DestroyImage(morph_image);
1315     }
1316     if (n < (ssize_t) number_frames)
1317       break;
1318     /*
1319       Clone last frame in sequence.
1320     */
1321     morph_image=CloneImage(GetNextImageInList(next),0,0,MagickTrue,exception);
1322     if (morph_image == (Image *) NULL)
1323       {
1324         morph_images=DestroyImageList(morph_images);
1325         return((Image *) NULL);
1326       }
1327     AppendImageToList(&morph_images,morph_image);
1328     morph_images=GetLastImageInList(morph_images);
1329     if (image->progress_monitor != (MagickProgressMonitor) NULL)
1330       {
1331         MagickBooleanType
1332           proceed;
1333 
1334         proceed=SetImageProgress(image,MorphImageTag,scene,
1335           GetImageListLength(image));
1336         if (proceed == MagickFalse)
1337           status=MagickFalse;
1338       }
1339     scene++;
1340   }
1341   if (GetNextImageInList(next) != (Image *) NULL)
1342     {
1343       morph_images=DestroyImageList(morph_images);
1344       return((Image *) NULL);
1345     }
1346   return(GetFirstImageInList(morph_images));
1347 }
1348 
1349 /*
1350 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1351 %                                                                             %
1352 %                                                                             %
1353 %                                                                             %
1354 %     P l a s m a I m a g e                                                   %
1355 %                                                                             %
1356 %                                                                             %
1357 %                                                                             %
1358 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1359 %
1360 %  PlasmaImage() initializes an image with plasma fractal values.  The image
1361 %  must be initialized with a base color and the random number generator
1362 %  seeded before this method is called.
1363 %
1364 %  The format of the PlasmaImage method is:
1365 %
1366 %      MagickBooleanType PlasmaImage(Image *image,const SegmentInfo *segment,
1367 %        size_t attenuate,size_t depth,ExceptionInfo *exception)
1368 %
1369 %  A description of each parameter follows:
1370 %
1371 %    o image: the image.
1372 %
1373 %    o segment:   Define the region to apply plasma fractals values.
1374 %
1375 %    o attenuate: Define the plasma attenuation factor.
1376 %
1377 %    o depth: Limit the plasma recursion depth.
1378 %
1379 %    o exception: return any errors or warnings in this structure.
1380 %
1381 */
1382 
PlasmaPixel(RandomInfo * magick_restrict random_info,const double pixel,const double noise)1383 static inline Quantum PlasmaPixel(RandomInfo *magick_restrict random_info,
1384   const double pixel,const double noise)
1385 {
1386   MagickRealType
1387     plasma;
1388 
1389   plasma=pixel+noise*GetPseudoRandomValue(random_info)-noise/2.0;
1390   return(ClampToQuantum(plasma));
1391 }
1392 
PlasmaImageProxy(Image * image,CacheView * image_view,CacheView * u_view,CacheView * v_view,RandomInfo * magick_restrict random_info,const SegmentInfo * magick_restrict segment,size_t attenuate,size_t depth,ExceptionInfo * exception)1393 static MagickBooleanType PlasmaImageProxy(Image *image,CacheView *image_view,
1394   CacheView *u_view,CacheView *v_view,RandomInfo *magick_restrict random_info,
1395   const SegmentInfo *magick_restrict segment,size_t attenuate,size_t depth,
1396   ExceptionInfo *exception)
1397 {
1398   double
1399     plasma;
1400 
1401   MagickBooleanType
1402     status;
1403 
1404   register const Quantum
1405     *magick_restrict u,
1406     *magick_restrict v;
1407 
1408   register Quantum
1409     *magick_restrict q;
1410 
1411   register ssize_t
1412     i;
1413 
1414   ssize_t
1415     x,
1416     x_mid,
1417     y,
1418     y_mid;
1419 
1420   if ((fabs(segment->x2-segment->x1) < MagickEpsilon) &&
1421       (fabs(segment->y2-segment->y1) < MagickEpsilon))
1422     return(MagickTrue);
1423   if (depth != 0)
1424     {
1425       SegmentInfo
1426         local_info;
1427 
1428       /*
1429         Divide the area into quadrants and recurse.
1430       */
1431       depth--;
1432       attenuate++;
1433       x_mid=(ssize_t) ceil((segment->x1+segment->x2)/2-0.5);
1434       y_mid=(ssize_t) ceil((segment->y1+segment->y2)/2-0.5);
1435       local_info=(*segment);
1436       local_info.x2=(double) x_mid;
1437       local_info.y2=(double) y_mid;
1438       status=PlasmaImageProxy(image,image_view,u_view,v_view,random_info,
1439         &local_info,attenuate,depth,exception);
1440       local_info=(*segment);
1441       local_info.y1=(double) y_mid;
1442       local_info.x2=(double) x_mid;
1443       status&=PlasmaImageProxy(image,image_view,u_view,v_view,random_info,
1444         &local_info,attenuate,depth,exception);
1445       local_info=(*segment);
1446       local_info.x1=(double) x_mid;
1447       local_info.y2=(double) y_mid;
1448       status&=PlasmaImageProxy(image,image_view,u_view,v_view,random_info,
1449         &local_info,attenuate,depth,exception);
1450       local_info=(*segment);
1451       local_info.x1=(double) x_mid;
1452       local_info.y1=(double) y_mid;
1453       status&=PlasmaImageProxy(image,image_view,u_view,v_view,random_info,
1454         &local_info,attenuate,depth,exception);
1455       return(status);
1456     }
1457   x_mid=(ssize_t) ceil((segment->x1+segment->x2)/2-0.5);
1458   y_mid=(ssize_t) ceil((segment->y1+segment->y2)/2-0.5);
1459   if ((fabs(segment->x1-x_mid) < MagickEpsilon) &&
1460       (fabs(segment->x2-x_mid) < MagickEpsilon) &&
1461       (fabs(segment->y1-y_mid) < MagickEpsilon) &&
1462       (fabs(segment->y2-y_mid) < MagickEpsilon))
1463     return(MagickFalse);
1464   /*
1465     Average pixels and apply plasma.
1466   */
1467   status=MagickTrue;
1468   plasma=(double) QuantumRange/(2.0*attenuate);
1469   if ((fabs(segment->x1-x_mid) >= MagickEpsilon) ||
1470       (fabs(segment->x2-x_mid) >= MagickEpsilon))
1471     {
1472       /*
1473         Left pixel.
1474       */
1475       x=(ssize_t) ceil(segment->x1-0.5);
1476       u=GetCacheViewVirtualPixels(u_view,x,(ssize_t) ceil(segment->y1-0.5),1,1,
1477         exception);
1478       v=GetCacheViewVirtualPixels(v_view,x,(ssize_t) ceil(segment->y2-0.5),1,1,
1479         exception);
1480       q=QueueCacheViewAuthenticPixels(image_view,x,y_mid,1,1,exception);
1481       if ((u == (const Quantum *) NULL) || (v == (const Quantum *) NULL) ||
1482           (q == (Quantum *) NULL))
1483         return(MagickTrue);
1484       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1485       {
1486         PixelChannel channel = GetPixelChannelChannel(image,i);
1487         PixelTrait traits = GetPixelChannelTraits(image,channel);
1488         if (traits == UndefinedPixelTrait)
1489           continue;
1490         q[i]=PlasmaPixel(random_info,((double) u[i]+v[i])/2.0,plasma);
1491       }
1492       status=SyncCacheViewAuthenticPixels(image_view,exception);
1493       if (fabs(segment->x1-segment->x2) >= MagickEpsilon)
1494         {
1495           /*
1496             Right pixel.
1497           */
1498           x=(ssize_t) ceil(segment->x2-0.5);
1499           u=GetCacheViewVirtualPixels(u_view,x,(ssize_t) ceil(segment->y1-0.5),
1500             1,1,exception);
1501           v=GetCacheViewVirtualPixels(v_view,x,(ssize_t) ceil(segment->y2-0.5),
1502             1,1,exception);
1503           q=QueueCacheViewAuthenticPixels(image_view,x,y_mid,1,1,exception);
1504           if ((u == (const Quantum *) NULL) || (v == (const Quantum *) NULL) ||
1505               (q == (Quantum *) NULL))
1506             return(MagickFalse);
1507           for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1508           {
1509             PixelChannel channel = GetPixelChannelChannel(image,i);
1510             PixelTrait traits = GetPixelChannelTraits(image,channel);
1511             if (traits == UndefinedPixelTrait)
1512               continue;
1513             q[i]=PlasmaPixel(random_info,((double) u[i]+v[i])/2.0,plasma);
1514           }
1515           status=SyncCacheViewAuthenticPixels(image_view,exception);
1516         }
1517     }
1518   if ((fabs(segment->y1-y_mid) >= MagickEpsilon) ||
1519       (fabs(segment->y2-y_mid) >= MagickEpsilon))
1520     {
1521       if ((fabs(segment->x1-x_mid) >= MagickEpsilon) ||
1522           (fabs(segment->y2-y_mid) >= MagickEpsilon))
1523         {
1524           /*
1525             Bottom pixel.
1526           */
1527           y=(ssize_t) ceil(segment->y2-0.5);
1528           u=GetCacheViewVirtualPixels(u_view,(ssize_t) ceil(segment->x1-0.5),y,
1529             1,1,exception);
1530           v=GetCacheViewVirtualPixels(v_view,(ssize_t) ceil(segment->x2-0.5),y,
1531             1,1,exception);
1532           q=QueueCacheViewAuthenticPixels(image_view,x_mid,y,1,1,exception);
1533           if ((u == (const Quantum *) NULL) || (v == (const Quantum *) NULL) ||
1534               (q == (Quantum *) NULL))
1535             return(MagickTrue);
1536           for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1537           {
1538             PixelChannel channel = GetPixelChannelChannel(image,i);
1539             PixelTrait traits = GetPixelChannelTraits(image,channel);
1540             if (traits == UndefinedPixelTrait)
1541               continue;
1542             q[i]=PlasmaPixel(random_info,((double) u[i]+v[i])/2.0,plasma);
1543           }
1544           status=SyncCacheViewAuthenticPixels(image_view,exception);
1545         }
1546       if (fabs(segment->y1-segment->y2) >= MagickEpsilon)
1547         {
1548           /*
1549             Top pixel.
1550           */
1551           y=(ssize_t) ceil(segment->y1-0.5);
1552           u=GetCacheViewVirtualPixels(u_view,(ssize_t) ceil(segment->x1-0.5),y,
1553             1,1,exception);
1554           v=GetCacheViewVirtualPixels(v_view,(ssize_t) ceil(segment->x2-0.5),y,
1555             1,1,exception);
1556           q=QueueCacheViewAuthenticPixels(image_view,x_mid,y,1,1,exception);
1557           if ((u == (const Quantum *) NULL) || (v == (const Quantum *) NULL) ||
1558               (q == (Quantum *) NULL))
1559             return(MagickTrue);
1560           for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1561           {
1562             PixelChannel channel = GetPixelChannelChannel(image,i);
1563             PixelTrait traits = GetPixelChannelTraits(image,channel);
1564             if (traits == UndefinedPixelTrait)
1565               continue;
1566             q[i]=PlasmaPixel(random_info,((double) u[i]+v[i])/2.0,plasma);
1567           }
1568           status=SyncCacheViewAuthenticPixels(image_view,exception);
1569         }
1570     }
1571   if ((fabs(segment->x1-segment->x2) >= MagickEpsilon) ||
1572       (fabs(segment->y1-segment->y2) >= MagickEpsilon))
1573     {
1574       /*
1575         Middle pixel.
1576       */
1577       x=(ssize_t) ceil(segment->x1-0.5);
1578       y=(ssize_t) ceil(segment->y1-0.5);
1579       u=GetCacheViewVirtualPixels(u_view,x,y,1,1,exception);
1580       x=(ssize_t) ceil(segment->x2-0.5);
1581       y=(ssize_t) ceil(segment->y2-0.5);
1582       v=GetCacheViewVirtualPixels(v_view,x,y,1,1,exception);
1583       q=QueueCacheViewAuthenticPixels(image_view,x_mid,y_mid,1,1,exception);
1584       if ((u == (const Quantum *) NULL) || (v == (const Quantum *) NULL) ||
1585           (q == (Quantum *) NULL))
1586         return(MagickTrue);
1587       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1588       {
1589         PixelChannel channel = GetPixelChannelChannel(image,i);
1590         PixelTrait traits = GetPixelChannelTraits(image,channel);
1591         if (traits == UndefinedPixelTrait)
1592           continue;
1593         q[i]=PlasmaPixel(random_info,((double) u[i]+v[i])/2.0,plasma);
1594       }
1595       status=SyncCacheViewAuthenticPixels(image_view,exception);
1596     }
1597   if ((fabs(segment->x2-segment->x1) < 3.0) &&
1598       (fabs(segment->y2-segment->y1) < 3.0))
1599     return(status);
1600   return(MagickFalse);
1601 }
1602 
PlasmaImage(Image * image,const SegmentInfo * segment,size_t attenuate,size_t depth,ExceptionInfo * exception)1603 MagickExport MagickBooleanType PlasmaImage(Image *image,
1604   const SegmentInfo *segment,size_t attenuate,size_t depth,
1605   ExceptionInfo *exception)
1606 {
1607   CacheView
1608     *image_view,
1609     *u_view,
1610     *v_view;
1611 
1612   MagickBooleanType
1613     status;
1614 
1615   RandomInfo
1616     *random_info;
1617 
1618   assert(image != (Image *) NULL);
1619   if (image->debug != MagickFalse)
1620     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1621   assert(image->signature == MagickCoreSignature);
1622   if (image->debug != MagickFalse)
1623     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1624   if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
1625     return(MagickFalse);
1626   image_view=AcquireAuthenticCacheView(image,exception);
1627   u_view=AcquireVirtualCacheView(image,exception);
1628   v_view=AcquireVirtualCacheView(image,exception);
1629   random_info=AcquireRandomInfo();
1630   status=PlasmaImageProxy(image,image_view,u_view,v_view,random_info,segment,
1631     attenuate,depth,exception);
1632   random_info=DestroyRandomInfo(random_info);
1633   v_view=DestroyCacheView(v_view);
1634   u_view=DestroyCacheView(u_view);
1635   image_view=DestroyCacheView(image_view);
1636   return(status);
1637 }
1638 
1639 /*
1640 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1641 %                                                                             %
1642 %                                                                             %
1643 %                                                                             %
1644 %   P o l a r o i d I m a g e                                                 %
1645 %                                                                             %
1646 %                                                                             %
1647 %                                                                             %
1648 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1649 %
1650 %  PolaroidImage() simulates a Polaroid picture.
1651 %
1652 %  The format of the PolaroidImage method is:
1653 %
1654 %      Image *PolaroidImage(const Image *image,const DrawInfo *draw_info,
1655 %        const char *caption,const double angle,
1656 %        const PixelInterpolateMethod method,ExceptionInfo exception)
1657 %
1658 %  A description of each parameter follows:
1659 %
1660 %    o image: the image.
1661 %
1662 %    o draw_info: the draw info.
1663 %
1664 %    o caption: the Polaroid caption.
1665 %
1666 %    o angle: Apply the effect along this angle.
1667 %
1668 %    o method: the pixel interpolation method.
1669 %
1670 %    o exception: return any errors or warnings in this structure.
1671 %
1672 */
PolaroidImage(const Image * image,const DrawInfo * draw_info,const char * caption,const double angle,const PixelInterpolateMethod method,ExceptionInfo * exception)1673 MagickExport Image *PolaroidImage(const Image *image,const DrawInfo *draw_info,
1674   const char *caption,const double angle,const PixelInterpolateMethod method,
1675   ExceptionInfo *exception)
1676 {
1677   Image
1678     *bend_image,
1679     *caption_image,
1680     *flop_image,
1681     *picture_image,
1682     *polaroid_image,
1683     *rotate_image,
1684     *trim_image;
1685 
1686   size_t
1687     height;
1688 
1689   ssize_t
1690     quantum;
1691 
1692   /*
1693     Simulate a Polaroid picture.
1694   */
1695   assert(image != (Image *) NULL);
1696   assert(image->signature == MagickCoreSignature);
1697   if (image->debug != MagickFalse)
1698     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1699   assert(exception != (ExceptionInfo *) NULL);
1700   assert(exception->signature == MagickCoreSignature);
1701   quantum=(ssize_t) MagickMax(MagickMax((double) image->columns,(double)
1702     image->rows)/25.0,10.0);
1703   height=image->rows+2*quantum;
1704   caption_image=(Image *) NULL;
1705   if (caption != (const char *) NULL)
1706     {
1707       char
1708         *text;
1709 
1710       /*
1711         Generate caption image.
1712       */
1713       caption_image=CloneImage(image,image->columns,1,MagickTrue,exception);
1714       if (caption_image == (Image *) NULL)
1715         return((Image *) NULL);
1716       text=InterpretImageProperties((ImageInfo *) NULL,(Image *) image,caption,
1717         exception);
1718       if (text != (char *) NULL)
1719         {
1720           char
1721             geometry[MagickPathExtent];
1722 
1723           DrawInfo
1724             *annotate_info;
1725 
1726           MagickBooleanType
1727             status;
1728 
1729           ssize_t
1730             count;
1731 
1732           TypeMetric
1733             metrics;
1734 
1735           annotate_info=CloneDrawInfo((const ImageInfo *) NULL,draw_info);
1736           (void) CloneString(&annotate_info->text,text);
1737           count=FormatMagickCaption(caption_image,annotate_info,MagickTrue,
1738             &metrics,&text,exception);
1739           status=SetImageExtent(caption_image,image->columns,(size_t)
1740             ((count+1)*(metrics.ascent-metrics.descent)+0.5),exception);
1741           if (status == MagickFalse)
1742             caption_image=DestroyImage(caption_image);
1743           else
1744             {
1745               caption_image->background_color=image->border_color;
1746               (void) SetImageBackgroundColor(caption_image,exception);
1747               (void) CloneString(&annotate_info->text,text);
1748               (void) FormatLocaleString(geometry,MagickPathExtent,"+0+%.20g",
1749                 metrics.ascent);
1750               if (annotate_info->gravity == UndefinedGravity)
1751                 (void) CloneString(&annotate_info->geometry,AcquireString(
1752                   geometry));
1753               (void) AnnotateImage(caption_image,annotate_info,exception);
1754               height+=caption_image->rows;
1755             }
1756           annotate_info=DestroyDrawInfo(annotate_info);
1757           text=DestroyString(text);
1758         }
1759     }
1760   picture_image=CloneImage(image,image->columns+2*quantum,height,MagickTrue,
1761     exception);
1762   if (picture_image == (Image *) NULL)
1763     {
1764       if (caption_image != (Image *) NULL)
1765         caption_image=DestroyImage(caption_image);
1766       return((Image *) NULL);
1767     }
1768   picture_image->background_color=image->border_color;
1769   (void) SetImageBackgroundColor(picture_image,exception);
1770   (void) CompositeImage(picture_image,image,OverCompositeOp,MagickTrue,quantum,
1771     quantum,exception);
1772   if (caption_image != (Image *) NULL)
1773     {
1774       (void) CompositeImage(picture_image,caption_image,OverCompositeOp,
1775         MagickTrue,quantum,(ssize_t) (image->rows+3*quantum/2),exception);
1776       caption_image=DestroyImage(caption_image);
1777     }
1778   (void) QueryColorCompliance("none",AllCompliance,
1779     &picture_image->background_color,exception);
1780   (void) SetImageAlphaChannel(picture_image,OpaqueAlphaChannel,exception);
1781   rotate_image=RotateImage(picture_image,90.0,exception);
1782   picture_image=DestroyImage(picture_image);
1783   if (rotate_image == (Image *) NULL)
1784     return((Image *) NULL);
1785   picture_image=rotate_image;
1786   bend_image=WaveImage(picture_image,0.01*picture_image->rows,2.0*
1787     picture_image->columns,method,exception);
1788   picture_image=DestroyImage(picture_image);
1789   if (bend_image == (Image *) NULL)
1790     return((Image *) NULL);
1791   picture_image=bend_image;
1792   rotate_image=RotateImage(picture_image,-90.0,exception);
1793   picture_image=DestroyImage(picture_image);
1794   if (rotate_image == (Image *) NULL)
1795     return((Image *) NULL);
1796   picture_image=rotate_image;
1797   picture_image->background_color=image->background_color;
1798   polaroid_image=ShadowImage(picture_image,80.0,2.0,quantum/3,quantum/3,
1799     exception);
1800   if (polaroid_image == (Image *) NULL)
1801     {
1802       picture_image=DestroyImage(picture_image);
1803       return(picture_image);
1804     }
1805   flop_image=FlopImage(polaroid_image,exception);
1806   polaroid_image=DestroyImage(polaroid_image);
1807   if (flop_image == (Image *) NULL)
1808     {
1809       picture_image=DestroyImage(picture_image);
1810       return(picture_image);
1811     }
1812   polaroid_image=flop_image;
1813   (void) CompositeImage(polaroid_image,picture_image,OverCompositeOp,
1814     MagickTrue,(ssize_t) (-0.01*picture_image->columns/2.0),0L,exception);
1815   picture_image=DestroyImage(picture_image);
1816   (void) QueryColorCompliance("none",AllCompliance,
1817     &polaroid_image->background_color,exception);
1818   rotate_image=RotateImage(polaroid_image,angle,exception);
1819   polaroid_image=DestroyImage(polaroid_image);
1820   if (rotate_image == (Image *) NULL)
1821     return((Image *) NULL);
1822   polaroid_image=rotate_image;
1823   trim_image=TrimImage(polaroid_image,exception);
1824   polaroid_image=DestroyImage(polaroid_image);
1825   if (trim_image == (Image *) NULL)
1826     return((Image *) NULL);
1827   polaroid_image=trim_image;
1828   return(polaroid_image);
1829 }
1830 
1831 /*
1832 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1833 %                                                                             %
1834 %                                                                             %
1835 %                                                                             %
1836 %     S e p i a T o n e I m a g e                                             %
1837 %                                                                             %
1838 %                                                                             %
1839 %                                                                             %
1840 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1841 %
1842 %  MagickSepiaToneImage() applies a special effect to the image, similar to the
1843 %  effect achieved in a photo darkroom by sepia toning.  Threshold ranges from
1844 %  0 to QuantumRange and is a measure of the extent of the sepia toning.  A
1845 %  threshold of 80% is a good starting point for a reasonable tone.
1846 %
1847 %  The format of the SepiaToneImage method is:
1848 %
1849 %      Image *SepiaToneImage(const Image *image,const double threshold,
1850 %        ExceptionInfo *exception)
1851 %
1852 %  A description of each parameter follows:
1853 %
1854 %    o image: the image.
1855 %
1856 %    o threshold: the tone threshold.
1857 %
1858 %    o exception: return any errors or warnings in this structure.
1859 %
1860 */
SepiaToneImage(const Image * image,const double threshold,ExceptionInfo * exception)1861 MagickExport Image *SepiaToneImage(const Image *image,const double threshold,
1862   ExceptionInfo *exception)
1863 {
1864 #define SepiaToneImageTag  "SepiaTone/Image"
1865 
1866   CacheView
1867     *image_view,
1868     *sepia_view;
1869 
1870   Image
1871     *sepia_image;
1872 
1873   MagickBooleanType
1874     status;
1875 
1876   MagickOffsetType
1877     progress;
1878 
1879   ssize_t
1880     y;
1881 
1882   /*
1883     Initialize sepia-toned image attributes.
1884   */
1885   assert(image != (const Image *) NULL);
1886   assert(image->signature == MagickCoreSignature);
1887   if (image->debug != MagickFalse)
1888     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1889   assert(exception != (ExceptionInfo *) NULL);
1890   assert(exception->signature == MagickCoreSignature);
1891   sepia_image=CloneImage(image,0,0,MagickTrue,exception);
1892   if (sepia_image == (Image *) NULL)
1893     return((Image *) NULL);
1894   if (SetImageStorageClass(sepia_image,DirectClass,exception) == MagickFalse)
1895     {
1896       sepia_image=DestroyImage(sepia_image);
1897       return((Image *) NULL);
1898     }
1899   /*
1900     Tone each row of the image.
1901   */
1902   status=MagickTrue;
1903   progress=0;
1904   image_view=AcquireVirtualCacheView(image,exception);
1905   sepia_view=AcquireAuthenticCacheView(sepia_image,exception);
1906 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1907   #pragma omp parallel for schedule(static) shared(progress,status) \
1908     magick_number_threads(image,sepia_image,image->rows,1)
1909 #endif
1910   for (y=0; y < (ssize_t) image->rows; y++)
1911   {
1912     register const Quantum
1913       *magick_restrict p;
1914 
1915     register ssize_t
1916       x;
1917 
1918     register Quantum
1919       *magick_restrict q;
1920 
1921     if (status == MagickFalse)
1922       continue;
1923     p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1924     q=GetCacheViewAuthenticPixels(sepia_view,0,y,sepia_image->columns,1,
1925       exception);
1926     if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
1927       {
1928         status=MagickFalse;
1929         continue;
1930       }
1931     for (x=0; x < (ssize_t) image->columns; x++)
1932     {
1933       double
1934         intensity,
1935         tone;
1936 
1937       intensity=GetPixelIntensity(image,p);
1938       tone=intensity > threshold ? (double) QuantumRange : intensity+
1939         (double) QuantumRange-threshold;
1940       SetPixelRed(sepia_image,ClampToQuantum(tone),q);
1941       tone=intensity > (7.0*threshold/6.0) ? (double) QuantumRange :
1942         intensity+(double) QuantumRange-7.0*threshold/6.0;
1943       SetPixelGreen(sepia_image,ClampToQuantum(tone),q);
1944       tone=intensity < (threshold/6.0) ? 0 : intensity-threshold/6.0;
1945       SetPixelBlue(sepia_image,ClampToQuantum(tone),q);
1946       tone=threshold/7.0;
1947       if ((double) GetPixelGreen(image,q) < tone)
1948         SetPixelGreen(sepia_image,ClampToQuantum(tone),q);
1949       if ((double) GetPixelBlue(image,q) < tone)
1950         SetPixelBlue(sepia_image,ClampToQuantum(tone),q);
1951       SetPixelAlpha(sepia_image,GetPixelAlpha(image,p),q);
1952       p+=GetPixelChannels(image);
1953       q+=GetPixelChannels(sepia_image);
1954     }
1955     if (SyncCacheViewAuthenticPixels(sepia_view,exception) == MagickFalse)
1956       status=MagickFalse;
1957     if (image->progress_monitor != (MagickProgressMonitor) NULL)
1958       {
1959         MagickBooleanType
1960           proceed;
1961 
1962 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1963         #pragma omp atomic
1964 #endif
1965         progress++;
1966         proceed=SetImageProgress(image,SepiaToneImageTag,progress,image->rows);
1967         if (proceed == MagickFalse)
1968           status=MagickFalse;
1969       }
1970   }
1971   sepia_view=DestroyCacheView(sepia_view);
1972   image_view=DestroyCacheView(image_view);
1973   (void) NormalizeImage(sepia_image,exception);
1974   (void) ContrastImage(sepia_image,MagickTrue,exception);
1975   if (status == MagickFalse)
1976     sepia_image=DestroyImage(sepia_image);
1977   return(sepia_image);
1978 }
1979 
1980 /*
1981 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1982 %                                                                             %
1983 %                                                                             %
1984 %                                                                             %
1985 %     S h a d o w I m a g e                                                   %
1986 %                                                                             %
1987 %                                                                             %
1988 %                                                                             %
1989 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1990 %
1991 %  ShadowImage() simulates a shadow from the specified image and returns it.
1992 %
1993 %  The format of the ShadowImage method is:
1994 %
1995 %      Image *ShadowImage(const Image *image,const double alpha,
1996 %        const double sigma,const ssize_t x_offset,const ssize_t y_offset,
1997 %        ExceptionInfo *exception)
1998 %
1999 %  A description of each parameter follows:
2000 %
2001 %    o image: the image.
2002 %
2003 %    o alpha: percentage transparency.
2004 %
2005 %    o sigma: the standard deviation of the Gaussian, in pixels.
2006 %
2007 %    o x_offset: the shadow x-offset.
2008 %
2009 %    o y_offset: the shadow y-offset.
2010 %
2011 %    o exception: return any errors or warnings in this structure.
2012 %
2013 */
ShadowImage(const Image * image,const double alpha,const double sigma,const ssize_t x_offset,const ssize_t y_offset,ExceptionInfo * exception)2014 MagickExport Image *ShadowImage(const Image *image,const double alpha,
2015   const double sigma,const ssize_t x_offset,const ssize_t y_offset,
2016   ExceptionInfo *exception)
2017 {
2018 #define ShadowImageTag  "Shadow/Image"
2019 
2020   CacheView
2021     *image_view;
2022 
2023   ChannelType
2024     channel_mask;
2025 
2026   Image
2027     *border_image,
2028     *clone_image,
2029     *shadow_image;
2030 
2031   MagickBooleanType
2032     status;
2033 
2034   PixelInfo
2035     background_color;
2036 
2037   RectangleInfo
2038     border_info;
2039 
2040   ssize_t
2041     y;
2042 
2043   assert(image != (Image *) NULL);
2044   assert(image->signature == MagickCoreSignature);
2045   if (image->debug != MagickFalse)
2046     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2047   assert(exception != (ExceptionInfo *) NULL);
2048   assert(exception->signature == MagickCoreSignature);
2049   clone_image=CloneImage(image,0,0,MagickTrue,exception);
2050   if (clone_image == (Image *) NULL)
2051     return((Image *) NULL);
2052   if (IsGrayColorspace(image->colorspace) != MagickFalse)
2053     (void) SetImageColorspace(clone_image,sRGBColorspace,exception);
2054   (void) SetImageVirtualPixelMethod(clone_image,EdgeVirtualPixelMethod,
2055     exception);
2056   border_info.width=(size_t) floor(2.0*sigma+0.5);
2057   border_info.height=(size_t) floor(2.0*sigma+0.5);
2058   border_info.x=0;
2059   border_info.y=0;
2060   (void) QueryColorCompliance("none",AllCompliance,&clone_image->border_color,
2061     exception);
2062   clone_image->alpha_trait=BlendPixelTrait;
2063   border_image=BorderImage(clone_image,&border_info,OverCompositeOp,exception);
2064   clone_image=DestroyImage(clone_image);
2065   if (border_image == (Image *) NULL)
2066     return((Image *) NULL);
2067   if (border_image->alpha_trait == UndefinedPixelTrait)
2068     (void) SetImageAlphaChannel(border_image,OpaqueAlphaChannel,exception);
2069   /*
2070     Shadow image.
2071   */
2072   status=MagickTrue;
2073   background_color=border_image->background_color;
2074   background_color.alpha_trait=BlendPixelTrait;
2075   image_view=AcquireAuthenticCacheView(border_image,exception);
2076   for (y=0; y < (ssize_t) border_image->rows; y++)
2077   {
2078     register Quantum
2079       *magick_restrict q;
2080 
2081     register ssize_t
2082       x;
2083 
2084     if (status == MagickFalse)
2085       continue;
2086     q=QueueCacheViewAuthenticPixels(image_view,0,y,border_image->columns,1,
2087       exception);
2088     if (q == (Quantum *) NULL)
2089       {
2090         status=MagickFalse;
2091         continue;
2092       }
2093     for (x=0; x < (ssize_t) border_image->columns; x++)
2094     {
2095       if (border_image->alpha_trait != UndefinedPixelTrait)
2096         background_color.alpha=GetPixelAlpha(border_image,q)*alpha/100.0;
2097       SetPixelViaPixelInfo(border_image,&background_color,q);
2098       q+=GetPixelChannels(border_image);
2099     }
2100     if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2101       status=MagickFalse;
2102   }
2103   image_view=DestroyCacheView(image_view);
2104   if (status == MagickFalse)
2105     {
2106       border_image=DestroyImage(border_image);
2107       return((Image *) NULL);
2108     }
2109   channel_mask=SetImageChannelMask(border_image,AlphaChannel);
2110   shadow_image=BlurImage(border_image,0.0,sigma,exception);
2111   border_image=DestroyImage(border_image);
2112   if (shadow_image == (Image *) NULL)
2113     return((Image *) NULL);
2114   (void) SetPixelChannelMask(shadow_image,channel_mask);
2115   if (shadow_image->page.width == 0)
2116     shadow_image->page.width=shadow_image->columns;
2117   if (shadow_image->page.height == 0)
2118     shadow_image->page.height=shadow_image->rows;
2119   shadow_image->page.width+=x_offset-(ssize_t) border_info.width;
2120   shadow_image->page.height+=y_offset-(ssize_t) border_info.height;
2121   shadow_image->page.x+=x_offset-(ssize_t) border_info.width;
2122   shadow_image->page.y+=y_offset-(ssize_t) border_info.height;
2123   return(shadow_image);
2124 }
2125 
2126 /*
2127 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2128 %                                                                             %
2129 %                                                                             %
2130 %                                                                             %
2131 %     S k e t c h I m a g e                                                   %
2132 %                                                                             %
2133 %                                                                             %
2134 %                                                                             %
2135 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2136 %
2137 %  SketchImage() simulates a pencil sketch.  We convolve the image with a
2138 %  Gaussian operator of the given radius and standard deviation (sigma).  For
2139 %  reasonable results, radius should be larger than sigma.  Use a radius of 0
2140 %  and SketchImage() selects a suitable radius for you.  Angle gives the angle
2141 %  of the sketch.
2142 %
2143 %  The format of the SketchImage method is:
2144 %
2145 %    Image *SketchImage(const Image *image,const double radius,
2146 %      const double sigma,const double angle,ExceptionInfo *exception)
2147 %
2148 %  A description of each parameter follows:
2149 %
2150 %    o image: the image.
2151 %
2152 %    o radius: the radius of the Gaussian, in pixels, not counting the
2153 %      center pixel.
2154 %
2155 %    o sigma: the standard deviation of the Gaussian, in pixels.
2156 %
2157 %    o angle: apply the effect along this angle.
2158 %
2159 %    o exception: return any errors or warnings in this structure.
2160 %
2161 */
SketchImage(const Image * image,const double radius,const double sigma,const double angle,ExceptionInfo * exception)2162 MagickExport Image *SketchImage(const Image *image,const double radius,
2163   const double sigma,const double angle,ExceptionInfo *exception)
2164 {
2165   CacheView
2166     *random_view;
2167 
2168   Image
2169     *blend_image,
2170     *blur_image,
2171     *dodge_image,
2172     *random_image,
2173     *sketch_image;
2174 
2175   MagickBooleanType
2176     status;
2177 
2178   RandomInfo
2179     **magick_restrict random_info;
2180 
2181   ssize_t
2182     y;
2183 
2184 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2185   unsigned long
2186     key;
2187 #endif
2188 
2189   /*
2190     Sketch image.
2191   */
2192   random_image=CloneImage(image,image->columns << 1,image->rows << 1,
2193     MagickTrue,exception);
2194   if (random_image == (Image *) NULL)
2195     return((Image *) NULL);
2196   status=MagickTrue;
2197   random_info=AcquireRandomInfoThreadSet();
2198   random_view=AcquireAuthenticCacheView(random_image,exception);
2199 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2200   key=GetRandomSecretKey(random_info[0]);
2201   #pragma omp parallel for schedule(static) shared(status) \
2202     magick_number_threads(random_image,random_image,random_image->rows,key == ~0UL)
2203 #endif
2204   for (y=0; y < (ssize_t) random_image->rows; y++)
2205   {
2206     const int
2207       id = GetOpenMPThreadId();
2208 
2209     register Quantum
2210       *magick_restrict q;
2211 
2212     register ssize_t
2213       x;
2214 
2215     if (status == MagickFalse)
2216       continue;
2217     q=QueueCacheViewAuthenticPixels(random_view,0,y,random_image->columns,1,
2218       exception);
2219     if (q == (Quantum *) NULL)
2220       {
2221         status=MagickFalse;
2222         continue;
2223       }
2224     for (x=0; x < (ssize_t) random_image->columns; x++)
2225     {
2226       double
2227         value;
2228 
2229       register ssize_t
2230         i;
2231 
2232       value=GetPseudoRandomValue(random_info[id]);
2233       for (i=0; i < (ssize_t) GetPixelChannels(random_image); i++)
2234       {
2235         PixelChannel channel = GetPixelChannelChannel(image,i);
2236         PixelTrait traits = GetPixelChannelTraits(image,channel);
2237         if (traits == UndefinedPixelTrait)
2238           continue;
2239         q[i]=ClampToQuantum(QuantumRange*value);
2240       }
2241       q+=GetPixelChannels(random_image);
2242     }
2243     if (SyncCacheViewAuthenticPixels(random_view,exception) == MagickFalse)
2244       status=MagickFalse;
2245   }
2246   random_view=DestroyCacheView(random_view);
2247   random_info=DestroyRandomInfoThreadSet(random_info);
2248   if (status == MagickFalse)
2249     {
2250       random_image=DestroyImage(random_image);
2251       return(random_image);
2252     }
2253   blur_image=MotionBlurImage(random_image,radius,sigma,angle,exception);
2254   random_image=DestroyImage(random_image);
2255   if (blur_image == (Image *) NULL)
2256     return((Image *) NULL);
2257   dodge_image=EdgeImage(blur_image,radius,exception);
2258   blur_image=DestroyImage(blur_image);
2259   if (dodge_image == (Image *) NULL)
2260     return((Image *) NULL);
2261   status=ClampImage(dodge_image,exception);
2262   if (status != MagickFalse)
2263     status=NormalizeImage(dodge_image,exception);
2264   if (status != MagickFalse)
2265     status=NegateImage(dodge_image,MagickFalse,exception);
2266   if (status != MagickFalse)
2267     status=TransformImage(&dodge_image,(char *) NULL,"50%",exception);
2268   sketch_image=CloneImage(image,0,0,MagickTrue,exception);
2269   if (sketch_image == (Image *) NULL)
2270     {
2271       dodge_image=DestroyImage(dodge_image);
2272       return((Image *) NULL);
2273     }
2274   (void) CompositeImage(sketch_image,dodge_image,ColorDodgeCompositeOp,
2275     MagickTrue,0,0,exception);
2276   dodge_image=DestroyImage(dodge_image);
2277   blend_image=CloneImage(image,0,0,MagickTrue,exception);
2278   if (blend_image == (Image *) NULL)
2279     {
2280       sketch_image=DestroyImage(sketch_image);
2281       return((Image *) NULL);
2282     }
2283   if (blend_image->alpha_trait != BlendPixelTrait)
2284     (void) SetImageAlpha(blend_image,TransparentAlpha,exception);
2285   (void) SetImageArtifact(blend_image,"compose:args","20x80");
2286   (void) CompositeImage(sketch_image,blend_image,BlendCompositeOp,MagickTrue,
2287     0,0,exception);
2288   blend_image=DestroyImage(blend_image);
2289   return(sketch_image);
2290 }
2291 
2292 /*
2293 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2294 %                                                                             %
2295 %                                                                             %
2296 %                                                                             %
2297 %     S o l a r i z e I m a g e                                               %
2298 %                                                                             %
2299 %                                                                             %
2300 %                                                                             %
2301 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2302 %
2303 %  SolarizeImage() applies a special effect to the image, similar to the effect
2304 %  achieved in a photo darkroom by selectively exposing areas of photo
2305 %  sensitive paper to light.  Threshold ranges from 0 to QuantumRange and is a
2306 %  measure of the extent of the solarization.
2307 %
2308 %  The format of the SolarizeImage method is:
2309 %
2310 %      MagickBooleanType SolarizeImage(Image *image,const double threshold,
2311 %        ExceptionInfo *exception)
2312 %
2313 %  A description of each parameter follows:
2314 %
2315 %    o image: the image.
2316 %
2317 %    o threshold:  Define the extent of the solarization.
2318 %
2319 %    o exception: return any errors or warnings in this structure.
2320 %
2321 */
SolarizeImage(Image * image,const double threshold,ExceptionInfo * exception)2322 MagickExport MagickBooleanType SolarizeImage(Image *image,
2323   const double threshold,ExceptionInfo *exception)
2324 {
2325 #define SolarizeImageTag  "Solarize/Image"
2326 
2327   CacheView
2328     *image_view;
2329 
2330   MagickBooleanType
2331     status;
2332 
2333   MagickOffsetType
2334     progress;
2335 
2336   ssize_t
2337     y;
2338 
2339   assert(image != (Image *) NULL);
2340   assert(image->signature == MagickCoreSignature);
2341   if (image->debug != MagickFalse)
2342     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2343   if (IsGrayColorspace(image->colorspace) != MagickFalse)
2344     (void) SetImageColorspace(image,sRGBColorspace,exception);
2345   if (image->storage_class == PseudoClass)
2346     {
2347       register ssize_t
2348         i;
2349 
2350       /*
2351         Solarize colormap.
2352       */
2353       for (i=0; i < (ssize_t) image->colors; i++)
2354       {
2355         if ((double) image->colormap[i].red > threshold)
2356           image->colormap[i].red=QuantumRange-image->colormap[i].red;
2357         if ((double) image->colormap[i].green > threshold)
2358           image->colormap[i].green=QuantumRange-image->colormap[i].green;
2359         if ((double) image->colormap[i].blue > threshold)
2360           image->colormap[i].blue=QuantumRange-image->colormap[i].blue;
2361       }
2362     }
2363   /*
2364     Solarize image.
2365   */
2366   status=MagickTrue;
2367   progress=0;
2368   image_view=AcquireAuthenticCacheView(image,exception);
2369 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2370   #pragma omp parallel for schedule(static) shared(progress,status) \
2371     magick_number_threads(image,image,image->rows,1)
2372 #endif
2373   for (y=0; y < (ssize_t) image->rows; y++)
2374   {
2375     register ssize_t
2376       x;
2377 
2378     register Quantum
2379       *magick_restrict q;
2380 
2381     if (status == MagickFalse)
2382       continue;
2383     q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2384     if (q == (Quantum *) NULL)
2385       {
2386         status=MagickFalse;
2387         continue;
2388       }
2389     for (x=0; x < (ssize_t) image->columns; x++)
2390     {
2391       register ssize_t
2392         i;
2393 
2394       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2395       {
2396         PixelChannel channel = GetPixelChannelChannel(image,i);
2397         PixelTrait traits = GetPixelChannelTraits(image,channel);
2398         if ((traits & UpdatePixelTrait) == 0)
2399           continue;
2400         if ((double) q[i] > threshold)
2401           q[i]=QuantumRange-q[i];
2402       }
2403       q+=GetPixelChannels(image);
2404     }
2405     if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2406       status=MagickFalse;
2407     if (image->progress_monitor != (MagickProgressMonitor) NULL)
2408       {
2409         MagickBooleanType
2410           proceed;
2411 
2412 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2413         #pragma omp atomic
2414 #endif
2415         progress++;
2416         proceed=SetImageProgress(image,SolarizeImageTag,progress,image->rows);
2417         if (proceed == MagickFalse)
2418           status=MagickFalse;
2419       }
2420   }
2421   image_view=DestroyCacheView(image_view);
2422   return(status);
2423 }
2424 
2425 /*
2426 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2427 %                                                                             %
2428 %                                                                             %
2429 %                                                                             %
2430 %   S t e g a n o I m a g e                                                   %
2431 %                                                                             %
2432 %                                                                             %
2433 %                                                                             %
2434 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2435 %
2436 %  SteganoImage() hides a digital watermark within the image.  Recover
2437 %  the hidden watermark later to prove that the authenticity of an image.
2438 %  Offset defines the start position within the image to hide the watermark.
2439 %
2440 %  The format of the SteganoImage method is:
2441 %
2442 %      Image *SteganoImage(const Image *image,Image *watermark,
2443 %        ExceptionInfo *exception)
2444 %
2445 %  A description of each parameter follows:
2446 %
2447 %    o image: the image.
2448 %
2449 %    o watermark: the watermark image.
2450 %
2451 %    o exception: return any errors or warnings in this structure.
2452 %
2453 */
SteganoImage(const Image * image,const Image * watermark,ExceptionInfo * exception)2454 MagickExport Image *SteganoImage(const Image *image,const Image *watermark,
2455   ExceptionInfo *exception)
2456 {
2457 #define GetBit(alpha,i) ((((size_t) (alpha) >> (size_t) (i)) & 0x01) != 0)
2458 #define SetBit(alpha,i,set) (Quantum) ((set) != 0 ? (size_t) (alpha) \
2459   | (one << (size_t) (i)) : (size_t) (alpha) & ~(one << (size_t) (i)))
2460 #define SteganoImageTag  "Stegano/Image"
2461 
2462   CacheView
2463     *stegano_view,
2464     *watermark_view;
2465 
2466   Image
2467     *stegano_image;
2468 
2469   int
2470     c;
2471 
2472   MagickBooleanType
2473     status;
2474 
2475   PixelInfo
2476     pixel;
2477 
2478   register Quantum
2479     *q;
2480 
2481   register ssize_t
2482     x;
2483 
2484   size_t
2485     depth,
2486     one;
2487 
2488   ssize_t
2489     i,
2490     j,
2491     k,
2492     y;
2493 
2494   /*
2495     Initialize steganographic image attributes.
2496   */
2497   assert(image != (const Image *) NULL);
2498   assert(image->signature == MagickCoreSignature);
2499   if (image->debug != MagickFalse)
2500     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2501   assert(watermark != (const Image *) NULL);
2502   assert(watermark->signature == MagickCoreSignature);
2503   assert(exception != (ExceptionInfo *) NULL);
2504   assert(exception->signature == MagickCoreSignature);
2505   one=1UL;
2506   stegano_image=CloneImage(image,0,0,MagickTrue,exception);
2507   if (stegano_image == (Image *) NULL)
2508     return((Image *) NULL);
2509   stegano_image->depth=MAGICKCORE_QUANTUM_DEPTH;
2510   if (SetImageStorageClass(stegano_image,DirectClass,exception) == MagickFalse)
2511     {
2512       stegano_image=DestroyImage(stegano_image);
2513       return((Image *) NULL);
2514     }
2515   /*
2516     Hide watermark in low-order bits of image.
2517   */
2518   c=0;
2519   i=0;
2520   j=0;
2521   depth=stegano_image->depth;
2522   k=stegano_image->offset;
2523   status=MagickTrue;
2524   watermark_view=AcquireVirtualCacheView(watermark,exception);
2525   stegano_view=AcquireAuthenticCacheView(stegano_image,exception);
2526   for (i=(ssize_t) depth-1; (i >= 0) && (j < (ssize_t) depth); i--)
2527   {
2528     for (y=0; (y < (ssize_t) watermark->rows) && (j < (ssize_t) depth); y++)
2529     {
2530       for (x=0; (x < (ssize_t) watermark->columns) && (j < (ssize_t) depth); x++)
2531       {
2532         ssize_t
2533           offset;
2534 
2535         (void) GetOneCacheViewVirtualPixelInfo(watermark_view,x,y,&pixel,
2536           exception);
2537         offset=k/(ssize_t) stegano_image->columns;
2538         if (offset >= (ssize_t) stegano_image->rows)
2539           break;
2540         q=GetCacheViewAuthenticPixels(stegano_view,k % (ssize_t)
2541           stegano_image->columns,k/(ssize_t) stegano_image->columns,1,1,
2542           exception);
2543         if (q == (Quantum *) NULL)
2544           break;
2545         switch (c)
2546         {
2547           case 0:
2548           {
2549             SetPixelRed(stegano_image,SetBit(GetPixelRed(stegano_image,q),j,
2550               GetBit(GetPixelInfoIntensity(stegano_image,&pixel),i)),q);
2551             break;
2552           }
2553           case 1:
2554           {
2555             SetPixelGreen(stegano_image,SetBit(GetPixelGreen(stegano_image,q),j,
2556               GetBit(GetPixelInfoIntensity(stegano_image,&pixel),i)),q);
2557             break;
2558           }
2559           case 2:
2560           {
2561             SetPixelBlue(stegano_image,SetBit(GetPixelBlue(stegano_image,q),j,
2562               GetBit(GetPixelInfoIntensity(stegano_image,&pixel),i)),q);
2563             break;
2564           }
2565         }
2566         if (SyncCacheViewAuthenticPixels(stegano_view,exception) == MagickFalse)
2567           break;
2568         c++;
2569         if (c == 3)
2570           c=0;
2571         k++;
2572         if (k == (ssize_t) (stegano_image->columns*stegano_image->columns))
2573           k=0;
2574         if (k == stegano_image->offset)
2575           j++;
2576       }
2577     }
2578     if (image->progress_monitor != (MagickProgressMonitor) NULL)
2579       {
2580         MagickBooleanType
2581           proceed;
2582 
2583         proceed=SetImageProgress(image,SteganoImageTag,(MagickOffsetType)
2584           (depth-i),depth);
2585         if (proceed == MagickFalse)
2586           status=MagickFalse;
2587       }
2588   }
2589   stegano_view=DestroyCacheView(stegano_view);
2590   watermark_view=DestroyCacheView(watermark_view);
2591   if (status == MagickFalse)
2592     stegano_image=DestroyImage(stegano_image);
2593   return(stegano_image);
2594 }
2595 
2596 /*
2597 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2598 %                                                                             %
2599 %                                                                             %
2600 %                                                                             %
2601 %   S t e r e o A n a g l y p h I m a g e                                     %
2602 %                                                                             %
2603 %                                                                             %
2604 %                                                                             %
2605 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2606 %
2607 %  StereoAnaglyphImage() combines two images and produces a single image that
2608 %  is the composite of a left and right image of a stereo pair.  Special
2609 %  red-green stereo glasses are required to view this effect.
2610 %
2611 %  The format of the StereoAnaglyphImage method is:
2612 %
2613 %      Image *StereoImage(const Image *left_image,const Image *right_image,
2614 %        ExceptionInfo *exception)
2615 %      Image *StereoAnaglyphImage(const Image *left_image,
2616 %        const Image *right_image,const ssize_t x_offset,const ssize_t y_offset,
2617 %        ExceptionInfo *exception)
2618 %
2619 %  A description of each parameter follows:
2620 %
2621 %    o left_image: the left image.
2622 %
2623 %    o right_image: the right image.
2624 %
2625 %    o exception: return any errors or warnings in this structure.
2626 %
2627 %    o x_offset: amount, in pixels, by which the left image is offset to the
2628 %      right of the right image.
2629 %
2630 %    o y_offset: amount, in pixels, by which the left image is offset to the
2631 %      bottom of the right image.
2632 %
2633 %
2634 */
StereoImage(const Image * left_image,const Image * right_image,ExceptionInfo * exception)2635 MagickExport Image *StereoImage(const Image *left_image,
2636   const Image *right_image,ExceptionInfo *exception)
2637 {
2638   return(StereoAnaglyphImage(left_image,right_image,0,0,exception));
2639 }
2640 
StereoAnaglyphImage(const Image * left_image,const Image * right_image,const ssize_t x_offset,const ssize_t y_offset,ExceptionInfo * exception)2641 MagickExport Image *StereoAnaglyphImage(const Image *left_image,
2642   const Image *right_image,const ssize_t x_offset,const ssize_t y_offset,
2643   ExceptionInfo *exception)
2644 {
2645 #define StereoImageTag  "Stereo/Image"
2646 
2647   const Image
2648     *image;
2649 
2650   Image
2651     *stereo_image;
2652 
2653   MagickBooleanType
2654     status;
2655 
2656   ssize_t
2657     y;
2658 
2659   assert(left_image != (const Image *) NULL);
2660   assert(left_image->signature == MagickCoreSignature);
2661   if (left_image->debug != MagickFalse)
2662     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2663       left_image->filename);
2664   assert(right_image != (const Image *) NULL);
2665   assert(right_image->signature == MagickCoreSignature);
2666   assert(exception != (ExceptionInfo *) NULL);
2667   assert(exception->signature == MagickCoreSignature);
2668   image=left_image;
2669   if ((left_image->columns != right_image->columns) ||
2670       (left_image->rows != right_image->rows))
2671     ThrowImageException(ImageError,"LeftAndRightImageSizesDiffer");
2672   /*
2673     Initialize stereo image attributes.
2674   */
2675   stereo_image=CloneImage(left_image,left_image->columns,left_image->rows,
2676     MagickTrue,exception);
2677   if (stereo_image == (Image *) NULL)
2678     return((Image *) NULL);
2679   if (SetImageStorageClass(stereo_image,DirectClass,exception) == MagickFalse)
2680     {
2681       stereo_image=DestroyImage(stereo_image);
2682       return((Image *) NULL);
2683     }
2684   (void) SetImageColorspace(stereo_image,sRGBColorspace,exception);
2685   /*
2686     Copy left image to red channel and right image to blue channel.
2687   */
2688   status=MagickTrue;
2689   for (y=0; y < (ssize_t) stereo_image->rows; y++)
2690   {
2691     register const Quantum
2692       *magick_restrict p,
2693       *magick_restrict q;
2694 
2695     register ssize_t
2696       x;
2697 
2698     register Quantum
2699       *magick_restrict r;
2700 
2701     p=GetVirtualPixels(left_image,-x_offset,y-y_offset,image->columns,1,
2702       exception);
2703     q=GetVirtualPixels(right_image,0,y,right_image->columns,1,exception);
2704     r=QueueAuthenticPixels(stereo_image,0,y,stereo_image->columns,1,exception);
2705     if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL) ||
2706         (r == (Quantum *) NULL))
2707       break;
2708     for (x=0; x < (ssize_t) stereo_image->columns; x++)
2709     {
2710       SetPixelRed(stereo_image,GetPixelRed(left_image,p),r);
2711       SetPixelGreen(stereo_image,GetPixelGreen(right_image,q),r);
2712       SetPixelBlue(stereo_image,GetPixelBlue(right_image,q),r);
2713       if ((GetPixelAlphaTraits(stereo_image) & CopyPixelTrait) != 0)
2714         SetPixelAlpha(stereo_image,(GetPixelAlpha(left_image,p)+
2715           GetPixelAlpha(right_image,q))/2,r);
2716       p+=GetPixelChannels(left_image);
2717       q+=GetPixelChannels(right_image);
2718       r+=GetPixelChannels(stereo_image);
2719     }
2720     if (SyncAuthenticPixels(stereo_image,exception) == MagickFalse)
2721       break;
2722     if (image->progress_monitor != (MagickProgressMonitor) NULL)
2723       {
2724         MagickBooleanType
2725           proceed;
2726 
2727         proceed=SetImageProgress(image,StereoImageTag,(MagickOffsetType) y,
2728           stereo_image->rows);
2729         if (proceed == MagickFalse)
2730           status=MagickFalse;
2731       }
2732   }
2733   if (status == MagickFalse)
2734     stereo_image=DestroyImage(stereo_image);
2735   return(stereo_image);
2736 }
2737 
2738 /*
2739 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2740 %                                                                             %
2741 %                                                                             %
2742 %                                                                             %
2743 %     S w i r l I m a g e                                                     %
2744 %                                                                             %
2745 %                                                                             %
2746 %                                                                             %
2747 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2748 %
2749 %  SwirlImage() swirls the pixels about the center of the image, where
2750 %  degrees indicates the sweep of the arc through which each pixel is moved.
2751 %  You get a more dramatic effect as the degrees move from 1 to 360.
2752 %
2753 %  The format of the SwirlImage method is:
2754 %
2755 %      Image *SwirlImage(const Image *image,double degrees,
2756 %        const PixelInterpolateMethod method,ExceptionInfo *exception)
2757 %
2758 %  A description of each parameter follows:
2759 %
2760 %    o image: the image.
2761 %
2762 %    o degrees: Define the tightness of the swirling effect.
2763 %
2764 %    o method: the pixel interpolation method.
2765 %
2766 %    o exception: return any errors or warnings in this structure.
2767 %
2768 */
SwirlImage(const Image * image,double degrees,const PixelInterpolateMethod method,ExceptionInfo * exception)2769 MagickExport Image *SwirlImage(const Image *image,double degrees,
2770   const PixelInterpolateMethod method,ExceptionInfo *exception)
2771 {
2772 #define SwirlImageTag  "Swirl/Image"
2773 
2774   CacheView
2775     *canvas_view,
2776     *interpolate_view,
2777     *swirl_view;
2778 
2779   double
2780     radius;
2781 
2782   Image
2783     *canvas_image,
2784     *swirl_image;
2785 
2786   MagickBooleanType
2787     status;
2788 
2789   MagickOffsetType
2790     progress;
2791 
2792   PointInfo
2793     center,
2794     scale;
2795 
2796   ssize_t
2797     y;
2798 
2799   /*
2800     Initialize swirl image attributes.
2801   */
2802   assert(image != (const Image *) NULL);
2803   assert(image->signature == MagickCoreSignature);
2804   if (image->debug != MagickFalse)
2805     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2806   assert(exception != (ExceptionInfo *) NULL);
2807   assert(exception->signature == MagickCoreSignature);
2808   canvas_image=CloneImage(image,0,0,MagickTrue,exception);
2809   if (canvas_image == (Image *) NULL)
2810     return((Image *) NULL);
2811   swirl_image=CloneImage(canvas_image,0,0,MagickTrue,exception);
2812   if (swirl_image == (Image *) NULL)
2813     {
2814       canvas_image=DestroyImage(canvas_image);
2815       return((Image *) NULL);
2816     }
2817   if (SetImageStorageClass(swirl_image,DirectClass,exception) == MagickFalse)
2818     {
2819       canvas_image=DestroyImage(canvas_image);
2820       swirl_image=DestroyImage(swirl_image);
2821       return((Image *) NULL);
2822     }
2823   if (swirl_image->background_color.alpha_trait != UndefinedPixelTrait)
2824     (void) SetImageAlphaChannel(swirl_image,OnAlphaChannel,exception);
2825   /*
2826     Compute scaling factor.
2827   */
2828   center.x=(double) canvas_image->columns/2.0;
2829   center.y=(double) canvas_image->rows/2.0;
2830   radius=MagickMax(center.x,center.y);
2831   scale.x=1.0;
2832   scale.y=1.0;
2833   if (canvas_image->columns > canvas_image->rows)
2834     scale.y=(double) canvas_image->columns/(double) canvas_image->rows;
2835   else
2836     if (canvas_image->columns < canvas_image->rows)
2837       scale.x=(double) canvas_image->rows/(double) canvas_image->columns;
2838   degrees=(double) DegreesToRadians(degrees);
2839   /*
2840     Swirl image.
2841   */
2842   status=MagickTrue;
2843   progress=0;
2844   canvas_view=AcquireVirtualCacheView(canvas_image,exception);
2845   interpolate_view=AcquireVirtualCacheView(image,exception);
2846   swirl_view=AcquireAuthenticCacheView(swirl_image,exception);
2847 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2848   #pragma omp parallel for schedule(static) shared(progress,status) \
2849     magick_number_threads(canvas_image,swirl_image,canvas_image->rows,1)
2850 #endif
2851   for (y=0; y < (ssize_t) canvas_image->rows; y++)
2852   {
2853     double
2854       distance;
2855 
2856     PointInfo
2857       delta;
2858 
2859     register const Quantum
2860       *magick_restrict p;
2861 
2862     register ssize_t
2863       x;
2864 
2865     register Quantum
2866       *magick_restrict q;
2867 
2868     if (status == MagickFalse)
2869       continue;
2870     p=GetCacheViewVirtualPixels(canvas_view,0,y,canvas_image->columns,1,
2871       exception);
2872     q=QueueCacheViewAuthenticPixels(swirl_view,0,y,swirl_image->columns,1,
2873       exception);
2874     if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
2875       {
2876         status=MagickFalse;
2877         continue;
2878       }
2879     delta.y=scale.y*(double) (y-center.y);
2880     for (x=0; x < (ssize_t) canvas_image->columns; x++)
2881     {
2882       /*
2883         Determine if the pixel is within an ellipse.
2884       */
2885       delta.x=scale.x*(double) (x-center.x);
2886       distance=delta.x*delta.x+delta.y*delta.y;
2887       if (distance >= (radius*radius))
2888         {
2889           register ssize_t
2890             i;
2891 
2892           for (i=0; i < (ssize_t) GetPixelChannels(canvas_image); i++)
2893           {
2894             PixelChannel channel = GetPixelChannelChannel(canvas_image,i);
2895             PixelTrait traits = GetPixelChannelTraits(canvas_image,channel);
2896             PixelTrait swirl_traits = GetPixelChannelTraits(swirl_image,
2897               channel);
2898             if ((traits == UndefinedPixelTrait) ||
2899                 (swirl_traits == UndefinedPixelTrait))
2900               continue;
2901             SetPixelChannel(swirl_image,channel,p[i],q);
2902           }
2903         }
2904       else
2905         {
2906           double
2907             cosine,
2908             factor,
2909             sine;
2910 
2911           /*
2912             Swirl the pixel.
2913           */
2914           factor=1.0-sqrt((double) distance)/radius;
2915           sine=sin((double) (degrees*factor*factor));
2916           cosine=cos((double) (degrees*factor*factor));
2917           status=InterpolatePixelChannels(canvas_image,interpolate_view,
2918             swirl_image,method,((cosine*delta.x-sine*delta.y)/scale.x+center.x),
2919             (double) ((sine*delta.x+cosine*delta.y)/scale.y+center.y),q,
2920             exception);
2921           if (status == MagickFalse)
2922             break;
2923         }
2924       p+=GetPixelChannels(canvas_image);
2925       q+=GetPixelChannels(swirl_image);
2926     }
2927     if (SyncCacheViewAuthenticPixels(swirl_view,exception) == MagickFalse)
2928       status=MagickFalse;
2929     if (canvas_image->progress_monitor != (MagickProgressMonitor) NULL)
2930       {
2931         MagickBooleanType
2932           proceed;
2933 
2934 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2935         #pragma omp atomic
2936 #endif
2937         progress++;
2938         proceed=SetImageProgress(canvas_image,SwirlImageTag,progress,
2939           canvas_image->rows);
2940         if (proceed == MagickFalse)
2941           status=MagickFalse;
2942       }
2943   }
2944   swirl_view=DestroyCacheView(swirl_view);
2945   interpolate_view=DestroyCacheView(interpolate_view);
2946   canvas_view=DestroyCacheView(canvas_view);
2947   canvas_image=DestroyImage(canvas_image);
2948   if (status == MagickFalse)
2949     swirl_image=DestroyImage(swirl_image);
2950   return(swirl_image);
2951 }
2952 
2953 /*
2954 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2955 %                                                                             %
2956 %                                                                             %
2957 %                                                                             %
2958 %     T i n t I m a g e                                                       %
2959 %                                                                             %
2960 %                                                                             %
2961 %                                                                             %
2962 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2963 %
2964 %  TintImage() applies a color vector to each pixel in the image.  The length
2965 %  of the vector is 0 for black and white and at its maximum for the midtones.
2966 %  The vector weighting function is f(x)=(1-(4.0*((x-0.5)*(x-0.5))))
2967 %
2968 %  The format of the TintImage method is:
2969 %
2970 %      Image *TintImage(const Image *image,const char *blend,
2971 %        const PixelInfo *tint,ExceptionInfo *exception)
2972 %
2973 %  A description of each parameter follows:
2974 %
2975 %    o image: the image.
2976 %
2977 %    o blend: A color value used for tinting.
2978 %
2979 %    o tint: A color value used for tinting.
2980 %
2981 %    o exception: return any errors or warnings in this structure.
2982 %
2983 */
TintImage(const Image * image,const char * blend,const PixelInfo * tint,ExceptionInfo * exception)2984 MagickExport Image *TintImage(const Image *image,const char *blend,
2985   const PixelInfo *tint,ExceptionInfo *exception)
2986 {
2987 #define TintImageTag  "Tint/Image"
2988 
2989   CacheView
2990     *image_view,
2991     *tint_view;
2992 
2993   double
2994     intensity;
2995 
2996   GeometryInfo
2997     geometry_info;
2998 
2999   Image
3000     *tint_image;
3001 
3002   MagickBooleanType
3003     status;
3004 
3005   MagickOffsetType
3006     progress;
3007 
3008   PixelInfo
3009     color_vector;
3010 
3011   MagickStatusType
3012     flags;
3013 
3014   ssize_t
3015     y;
3016 
3017   /*
3018     Allocate tint image.
3019   */
3020   assert(image != (const Image *) NULL);
3021   assert(image->signature == MagickCoreSignature);
3022   if (image->debug != MagickFalse)
3023     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3024   assert(exception != (ExceptionInfo *) NULL);
3025   assert(exception->signature == MagickCoreSignature);
3026   tint_image=CloneImage(image,0,0,MagickTrue,exception);
3027   if (tint_image == (Image *) NULL)
3028     return((Image *) NULL);
3029   if (SetImageStorageClass(tint_image,DirectClass,exception) == MagickFalse)
3030     {
3031       tint_image=DestroyImage(tint_image);
3032       return((Image *) NULL);
3033     }
3034   if ((IsGrayColorspace(image->colorspace) != MagickFalse) &&
3035       (IsPixelInfoGray(tint) == MagickFalse))
3036     (void) SetImageColorspace(tint_image,sRGBColorspace,exception);
3037   if (blend == (const char *) NULL)
3038     return(tint_image);
3039   /*
3040     Determine RGB values of the color.
3041   */
3042   GetPixelInfo(image,&color_vector);
3043   flags=ParseGeometry(blend,&geometry_info);
3044   color_vector.red=geometry_info.rho;
3045   color_vector.green=geometry_info.rho;
3046   color_vector.blue=geometry_info.rho;
3047   color_vector.alpha=(MagickRealType) OpaqueAlpha;
3048   if ((flags & SigmaValue) != 0)
3049     color_vector.green=geometry_info.sigma;
3050   if ((flags & XiValue) != 0)
3051     color_vector.blue=geometry_info.xi;
3052   if ((flags & PsiValue) != 0)
3053     color_vector.alpha=geometry_info.psi;
3054   if (image->colorspace == CMYKColorspace)
3055     {
3056       color_vector.black=geometry_info.rho;
3057       if ((flags & PsiValue) != 0)
3058         color_vector.black=geometry_info.psi;
3059       if ((flags & ChiValue) != 0)
3060         color_vector.alpha=geometry_info.chi;
3061     }
3062   intensity=(double) GetPixelInfoIntensity((const Image *) NULL,tint);
3063   color_vector.red=(double) (color_vector.red*tint->red/100.0-intensity);
3064   color_vector.green=(double) (color_vector.green*tint->green/100.0-intensity);
3065   color_vector.blue=(double) (color_vector.blue*tint->blue/100.0-intensity);
3066   color_vector.black=(double) (color_vector.black*tint->black/100.0-intensity);
3067   color_vector.alpha=(double) (color_vector.alpha*tint->alpha/100.0-intensity);
3068   /*
3069     Tint image.
3070   */
3071   status=MagickTrue;
3072   progress=0;
3073   image_view=AcquireVirtualCacheView(image,exception);
3074   tint_view=AcquireAuthenticCacheView(tint_image,exception);
3075 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3076   #pragma omp parallel for schedule(static) shared(progress,status) \
3077     magick_number_threads(image,tint_image,image->rows,1)
3078 #endif
3079   for (y=0; y < (ssize_t) image->rows; y++)
3080   {
3081     register const Quantum
3082       *magick_restrict p;
3083 
3084     register Quantum
3085       *magick_restrict q;
3086 
3087     register ssize_t
3088       x;
3089 
3090     if (status == MagickFalse)
3091       continue;
3092     p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
3093     q=QueueCacheViewAuthenticPixels(tint_view,0,y,tint_image->columns,1,
3094       exception);
3095     if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
3096       {
3097         status=MagickFalse;
3098         continue;
3099       }
3100     for (x=0; x < (ssize_t) image->columns; x++)
3101     {
3102       PixelInfo
3103         pixel;
3104 
3105       double
3106         weight;
3107 
3108       GetPixelInfo(image,&pixel);
3109       weight=QuantumScale*GetPixelRed(image,p)-0.5;
3110       pixel.red=(MagickRealType) GetPixelRed(image,p)+color_vector.red*
3111         (1.0-(4.0*(weight*weight)));
3112       weight=QuantumScale*GetPixelGreen(image,p)-0.5;
3113       pixel.green=(MagickRealType) GetPixelGreen(image,p)+color_vector.green*
3114         (1.0-(4.0*(weight*weight)));
3115       weight=QuantumScale*GetPixelBlue(image,p)-0.5;
3116       pixel.blue=(MagickRealType) GetPixelBlue(image,p)+color_vector.blue*
3117         (1.0-(4.0*(weight*weight)));
3118       weight=QuantumScale*GetPixelBlack(image,p)-0.5;
3119       pixel.black=(MagickRealType) GetPixelBlack(image,p)+color_vector.black*
3120         (1.0-(4.0*(weight*weight)));
3121       pixel.alpha=(MagickRealType) GetPixelAlpha(image,p);
3122       SetPixelViaPixelInfo(tint_image,&pixel,q);
3123       p+=GetPixelChannels(image);
3124       q+=GetPixelChannels(tint_image);
3125     }
3126     if (SyncCacheViewAuthenticPixels(tint_view,exception) == MagickFalse)
3127       status=MagickFalse;
3128     if (image->progress_monitor != (MagickProgressMonitor) NULL)
3129       {
3130         MagickBooleanType
3131           proceed;
3132 
3133 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3134         #pragma omp atomic
3135 #endif
3136         progress++;
3137         proceed=SetImageProgress(image,TintImageTag,progress,image->rows);
3138         if (proceed == MagickFalse)
3139           status=MagickFalse;
3140       }
3141   }
3142   tint_view=DestroyCacheView(tint_view);
3143   image_view=DestroyCacheView(image_view);
3144   if (status == MagickFalse)
3145     tint_image=DestroyImage(tint_image);
3146   return(tint_image);
3147 }
3148 
3149 /*
3150 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3151 %                                                                             %
3152 %                                                                             %
3153 %                                                                             %
3154 %     V i g n e t t e I m a g e                                               %
3155 %                                                                             %
3156 %                                                                             %
3157 %                                                                             %
3158 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3159 %
3160 %  VignetteImage() softens the edges of the image in vignette style.
3161 %
3162 %  The format of the VignetteImage method is:
3163 %
3164 %      Image *VignetteImage(const Image *image,const double radius,
3165 %        const double sigma,const ssize_t x,const ssize_t y,
3166 %        ExceptionInfo *exception)
3167 %
3168 %  A description of each parameter follows:
3169 %
3170 %    o image: the image.
3171 %
3172 %    o radius: the radius of the pixel neighborhood.
3173 %
3174 %    o sigma: the standard deviation of the Gaussian, in pixels.
3175 %
3176 %    o x, y:  Define the x and y ellipse offset.
3177 %
3178 %    o exception: return any errors or warnings in this structure.
3179 %
3180 */
VignetteImage(const Image * image,const double radius,const double sigma,const ssize_t x,const ssize_t y,ExceptionInfo * exception)3181 MagickExport Image *VignetteImage(const Image *image,const double radius,
3182   const double sigma,const ssize_t x,const ssize_t y,ExceptionInfo *exception)
3183 {
3184   char
3185     ellipse[MagickPathExtent];
3186 
3187   DrawInfo
3188     *draw_info;
3189 
3190   Image
3191     *canvas,
3192     *blur_image,
3193     *oval_image,
3194     *vignette_image;
3195 
3196   assert(image != (Image *) NULL);
3197   assert(image->signature == MagickCoreSignature);
3198   if (image->debug != MagickFalse)
3199     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3200   assert(exception != (ExceptionInfo *) NULL);
3201   assert(exception->signature == MagickCoreSignature);
3202   canvas=CloneImage(image,0,0,MagickTrue,exception);
3203   if (canvas == (Image *) NULL)
3204     return((Image *) NULL);
3205   if (SetImageStorageClass(canvas,DirectClass,exception) == MagickFalse)
3206     {
3207       canvas=DestroyImage(canvas);
3208       return((Image *) NULL);
3209     }
3210   canvas->alpha_trait=BlendPixelTrait;
3211   oval_image=CloneImage(canvas,canvas->columns,canvas->rows,MagickTrue,
3212     exception);
3213   if (oval_image == (Image *) NULL)
3214     {
3215       canvas=DestroyImage(canvas);
3216       return((Image *) NULL);
3217     }
3218   (void) QueryColorCompliance("#000000",AllCompliance,
3219     &oval_image->background_color,exception);
3220   (void) SetImageBackgroundColor(oval_image,exception);
3221   draw_info=CloneDrawInfo((const ImageInfo *) NULL,(const DrawInfo *) NULL);
3222   (void) QueryColorCompliance("#ffffff",AllCompliance,&draw_info->fill,
3223     exception);
3224   (void) QueryColorCompliance("#ffffff",AllCompliance,&draw_info->stroke,
3225     exception);
3226   (void) FormatLocaleString(ellipse,MagickPathExtent,"ellipse %g,%g,%g,%g,"
3227     "0.0,360.0",image->columns/2.0,image->rows/2.0,image->columns/2.0-x,
3228     image->rows/2.0-y);
3229   draw_info->primitive=AcquireString(ellipse);
3230   (void) DrawImage(oval_image,draw_info,exception);
3231   draw_info=DestroyDrawInfo(draw_info);
3232   blur_image=BlurImage(oval_image,radius,sigma,exception);
3233   oval_image=DestroyImage(oval_image);
3234   if (blur_image == (Image *) NULL)
3235     {
3236       canvas=DestroyImage(canvas);
3237       return((Image *) NULL);
3238     }
3239   blur_image->alpha_trait=UndefinedPixelTrait;
3240   (void) CompositeImage(canvas,blur_image,IntensityCompositeOp,MagickTrue,
3241     0,0,exception);
3242   blur_image=DestroyImage(blur_image);
3243   vignette_image=MergeImageLayers(canvas,FlattenLayer,exception);
3244   canvas=DestroyImage(canvas);
3245   if (vignette_image != (Image *) NULL)
3246     (void) TransformImageColorspace(vignette_image,image->colorspace,exception);
3247   return(vignette_image);
3248 }
3249 
3250 /*
3251 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3252 %                                                                             %
3253 %                                                                             %
3254 %                                                                             %
3255 %     W a v e I m a g e                                                       %
3256 %                                                                             %
3257 %                                                                             %
3258 %                                                                             %
3259 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3260 %
3261 %  WaveImage() creates a "ripple" effect in the image by shifting the pixels
3262 %  vertically along a sine wave whose amplitude and wavelength is specified
3263 %  by the given parameters.
3264 %
3265 %  The format of the WaveImage method is:
3266 %
3267 %      Image *WaveImage(const Image *image,const double amplitude,
3268 %        const double wave_length,const PixelInterpolateMethod method,
3269 %        ExceptionInfo *exception)
3270 %
3271 %  A description of each parameter follows:
3272 %
3273 %    o image: the image.
3274 %
3275 %    o amplitude, wave_length:  Define the amplitude and wave length of the
3276 %      sine wave.
3277 %
3278 %    o interpolate: the pixel interpolation method.
3279 %
3280 %    o exception: return any errors or warnings in this structure.
3281 %
3282 */
WaveImage(const Image * image,const double amplitude,const double wave_length,const PixelInterpolateMethod method,ExceptionInfo * exception)3283 MagickExport Image *WaveImage(const Image *image,const double amplitude,
3284   const double wave_length,const PixelInterpolateMethod method,
3285   ExceptionInfo *exception)
3286 {
3287 #define WaveImageTag  "Wave/Image"
3288 
3289   CacheView
3290     *canvas_image_view,
3291     *wave_view;
3292 
3293   float
3294     *sine_map;
3295 
3296   Image
3297     *canvas_image,
3298     *wave_image;
3299 
3300   MagickBooleanType
3301     status;
3302 
3303   MagickOffsetType
3304     progress;
3305 
3306   register ssize_t
3307     i;
3308 
3309   ssize_t
3310     y;
3311 
3312   /*
3313     Initialize wave image attributes.
3314   */
3315   assert(image != (Image *) NULL);
3316   assert(image->signature == MagickCoreSignature);
3317   if (image->debug != MagickFalse)
3318     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3319   assert(exception != (ExceptionInfo *) NULL);
3320   assert(exception->signature == MagickCoreSignature);
3321   canvas_image=CloneImage(image,0,0,MagickTrue,exception);
3322   if (canvas_image == (Image *) NULL)
3323     return((Image *) NULL);
3324   if ((canvas_image->alpha_trait == UndefinedPixelTrait) &&
3325       (canvas_image->background_color.alpha != OpaqueAlpha))
3326     (void) SetImageAlpha(canvas_image,OpaqueAlpha,exception);
3327   wave_image=CloneImage(canvas_image,canvas_image->columns,(size_t)
3328     (canvas_image->rows+2.0*fabs(amplitude)),MagickTrue,exception);
3329   if (wave_image == (Image *) NULL)
3330     {
3331       canvas_image=DestroyImage(canvas_image);
3332       return((Image *) NULL);
3333     }
3334   if (SetImageStorageClass(wave_image,DirectClass,exception) == MagickFalse)
3335     {
3336       canvas_image=DestroyImage(canvas_image);
3337       wave_image=DestroyImage(wave_image);
3338       return((Image *) NULL);
3339     }
3340   /*
3341     Allocate sine map.
3342   */
3343   sine_map=(float *) AcquireQuantumMemory((size_t) wave_image->columns,
3344     sizeof(*sine_map));
3345   if (sine_map == (float *) NULL)
3346     {
3347       canvas_image=DestroyImage(canvas_image);
3348       wave_image=DestroyImage(wave_image);
3349       ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
3350     }
3351   for (i=0; i < (ssize_t) wave_image->columns; i++)
3352     sine_map[i]=(float) fabs(amplitude)+amplitude*sin((double)
3353       ((2.0*MagickPI*i)/wave_length));
3354   /*
3355     Wave image.
3356   */
3357   status=MagickTrue;
3358   progress=0;
3359   canvas_image_view=AcquireVirtualCacheView(canvas_image,exception);
3360   wave_view=AcquireAuthenticCacheView(wave_image,exception);
3361   (void) SetCacheViewVirtualPixelMethod(canvas_image_view,
3362     BackgroundVirtualPixelMethod);
3363 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3364   #pragma omp parallel for schedule(static) shared(progress,status) \
3365     magick_number_threads(canvas_image,wave_image,wave_image->rows,1)
3366 #endif
3367   for (y=0; y < (ssize_t) wave_image->rows; y++)
3368   {
3369     register const Quantum
3370       *magick_restrict p;
3371 
3372     register Quantum
3373       *magick_restrict q;
3374 
3375     register ssize_t
3376       x;
3377 
3378     if (status == MagickFalse)
3379       continue;
3380     p=GetCacheViewVirtualPixels(canvas_image_view,0,y,canvas_image->columns,1,
3381       exception);
3382     q=QueueCacheViewAuthenticPixels(wave_view,0,y,wave_image->columns,1,
3383       exception);
3384     if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
3385       {
3386         status=MagickFalse;
3387         continue;
3388       }
3389     for (x=0; x < (ssize_t) wave_image->columns; x++)
3390     {
3391       status=InterpolatePixelChannels(canvas_image,canvas_image_view,
3392         wave_image,method,(double) x,(double) (y-sine_map[x]),q,exception);
3393       if (status == MagickFalse)
3394         break;
3395       p+=GetPixelChannels(canvas_image);
3396       q+=GetPixelChannels(wave_image);
3397     }
3398     if (SyncCacheViewAuthenticPixels(wave_view,exception) == MagickFalse)
3399       status=MagickFalse;
3400     if (image->progress_monitor != (MagickProgressMonitor) NULL)
3401       {
3402         MagickBooleanType
3403           proceed;
3404 
3405 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3406         #pragma omp atomic
3407 #endif
3408         progress++;
3409         proceed=SetImageProgress(canvas_image,WaveImageTag,progress,
3410           canvas_image->rows);
3411         if (proceed == MagickFalse)
3412           status=MagickFalse;
3413       }
3414   }
3415   wave_view=DestroyCacheView(wave_view);
3416   canvas_image_view=DestroyCacheView(canvas_image_view);
3417   canvas_image=DestroyImage(canvas_image);
3418   sine_map=(float *) RelinquishMagickMemory(sine_map);
3419   if (status == MagickFalse)
3420     wave_image=DestroyImage(wave_image);
3421   return(wave_image);
3422 }
3423 
3424 /*
3425 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3426 %                                                                             %
3427 %                                                                             %
3428 %                                                                             %
3429 %     W a v e l e t D e n o i s e I m a g e                                   %
3430 %                                                                             %
3431 %                                                                             %
3432 %                                                                             %
3433 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3434 %
3435 %  WaveletDenoiseImage() removes noise from the image using a wavelet
3436 %  transform.  The wavelet transform is a fast hierarchical scheme for
3437 %  processing an image using a set of consecutive lowpass and high_pass filters,
3438 %  followed by a decimation.  This results in a decomposition into different
3439 %  scales which can be regarded as different “frequency bands”, determined by
3440 %  the mother wavelet.  Adapted from dcraw.c by David Coffin.
3441 %
3442 %  The format of the WaveletDenoiseImage method is:
3443 %
3444 %      Image *WaveletDenoiseImage(const Image *image,const double threshold,
3445 %        const double softness,ExceptionInfo *exception)
3446 %
3447 %  A description of each parameter follows:
3448 %
3449 %    o image: the image.
3450 %
3451 %    o threshold: set the threshold for smoothing.
3452 %
3453 %    o softness: attenuate the smoothing threshold.
3454 %
3455 %    o exception: return any errors or warnings in this structure.
3456 %
3457 */
3458 
HatTransform(const float * magick_restrict pixels,const size_t stride,const size_t extent,const size_t scale,float * kernel)3459 static inline void HatTransform(const float *magick_restrict pixels,
3460   const size_t stride,const size_t extent,const size_t scale,float *kernel)
3461 {
3462   const float
3463     *magick_restrict p,
3464     *magick_restrict q,
3465     *magick_restrict r;
3466 
3467   register ssize_t
3468     i;
3469 
3470   p=pixels;
3471   q=pixels+scale*stride;
3472   r=pixels+scale*stride;
3473   for (i=0; i < (ssize_t) scale; i++)
3474   {
3475     kernel[i]=0.25f*(*p+(*p)+(*q)+(*r));
3476     p+=stride;
3477     q-=stride;
3478     r+=stride;
3479   }
3480   for ( ; i < (ssize_t) (extent-scale); i++)
3481   {
3482     kernel[i]=0.25f*(2.0f*(*p)+*(p-scale*stride)+*(p+scale*stride));
3483     p+=stride;
3484   }
3485   q=p-scale*stride;
3486   r=pixels+stride*(extent-2);
3487   for ( ; i < (ssize_t) extent; i++)
3488   {
3489     kernel[i]=0.25f*(*p+(*p)+(*q)+(*r));
3490     p+=stride;
3491     q+=stride;
3492     r-=stride;
3493   }
3494 }
3495 
WaveletDenoiseImage(const Image * image,const double threshold,const double softness,ExceptionInfo * exception)3496 MagickExport Image *WaveletDenoiseImage(const Image *image,
3497   const double threshold,const double softness,ExceptionInfo *exception)
3498 {
3499   CacheView
3500     *image_view,
3501     *noise_view;
3502 
3503   float
3504     *kernel,
3505     *pixels;
3506 
3507   Image
3508     *noise_image;
3509 
3510   MagickBooleanType
3511     status;
3512 
3513   MagickSizeType
3514     number_pixels;
3515 
3516   MemoryInfo
3517     *pixels_info;
3518 
3519   ssize_t
3520     channel;
3521 
3522   static const float
3523     noise_levels[] = { 0.8002f, 0.2735f, 0.1202f, 0.0585f, 0.0291f, 0.0152f,
3524       0.0080f, 0.0044f };
3525 
3526   /*
3527     Initialize noise image attributes.
3528   */
3529   assert(image != (const Image *) NULL);
3530   assert(image->signature == MagickCoreSignature);
3531   if (image->debug != MagickFalse)
3532     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3533   assert(exception != (ExceptionInfo *) NULL);
3534   assert(exception->signature == MagickCoreSignature);
3535 #if defined(MAGICKCORE_OPENCL_SUPPORT)
3536   noise_image=AccelerateWaveletDenoiseImage(image,threshold,exception);
3537   if (noise_image != (Image *) NULL)
3538     return(noise_image);
3539 #endif
3540   noise_image=CloneImage(image,0,0,MagickTrue,exception);
3541   if (noise_image == (Image *) NULL)
3542     return((Image *) NULL);
3543   if (SetImageStorageClass(noise_image,DirectClass,exception) == MagickFalse)
3544     {
3545       noise_image=DestroyImage(noise_image);
3546       return((Image *) NULL);
3547     }
3548   if (AcquireMagickResource(WidthResource,4*image->columns) == MagickFalse)
3549     ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
3550   pixels_info=AcquireVirtualMemory(3*image->columns,image->rows*
3551     sizeof(*pixels));
3552   kernel=(float *) AcquireQuantumMemory(MagickMax(image->rows,image->columns)+1,
3553     GetOpenMPMaximumThreads()*sizeof(*kernel));
3554   if ((pixels_info == (MemoryInfo *) NULL) || (kernel == (float *) NULL))
3555     {
3556       if (kernel != (float *) NULL)
3557         kernel=(float *) RelinquishMagickMemory(kernel);
3558       if (pixels_info != (MemoryInfo *) NULL)
3559         pixels_info=RelinquishVirtualMemory(pixels_info);
3560       ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
3561     }
3562   pixels=(float *) GetVirtualMemoryBlob(pixels_info);
3563   status=MagickTrue;
3564   number_pixels=(MagickSizeType) image->columns*image->rows;
3565   image_view=AcquireAuthenticCacheView(image,exception);
3566   noise_view=AcquireAuthenticCacheView(noise_image,exception);
3567   for (channel=0; channel < (ssize_t) GetPixelChannels(image); channel++)
3568   {
3569     register ssize_t
3570       i;
3571 
3572     size_t
3573       high_pass,
3574       low_pass;
3575 
3576     ssize_t
3577       level,
3578       y;
3579 
3580     PixelChannel
3581       pixel_channel;
3582 
3583     PixelTrait
3584       traits;
3585 
3586     if (status == MagickFalse)
3587       continue;
3588     traits=GetPixelChannelTraits(image,(PixelChannel) channel);
3589     if (traits == UndefinedPixelTrait)
3590       continue;
3591     pixel_channel=GetPixelChannelChannel(image,channel);
3592     if ((pixel_channel != RedPixelChannel) &&
3593         (pixel_channel != GreenPixelChannel) &&
3594         (pixel_channel != BluePixelChannel))
3595       continue;
3596     /*
3597       Copy channel from image to wavelet pixel array.
3598     */
3599     i=0;
3600     for (y=0; y < (ssize_t) image->rows; y++)
3601     {
3602       register const Quantum
3603         *magick_restrict p;
3604 
3605       ssize_t
3606         x;
3607 
3608       p=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
3609       if (p == (const Quantum *) NULL)
3610         {
3611           status=MagickFalse;
3612           break;
3613         }
3614       for (x=0; x < (ssize_t) image->columns; x++)
3615       {
3616         pixels[i++]=(float) p[channel];
3617         p+=GetPixelChannels(image);
3618       }
3619     }
3620     /*
3621       Low pass filter outputs are called approximation kernel & high pass
3622       filters are referred to as detail kernel. The detail kernel
3623       have high values in the noisy parts of the signal.
3624     */
3625     high_pass=0;
3626     for (level=0; level < 5; level++)
3627     {
3628       double
3629         magnitude;
3630 
3631       ssize_t
3632         x,
3633         y;
3634 
3635       low_pass=(size_t) (number_pixels*((level & 0x01)+1));
3636 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3637       #pragma omp parallel for schedule(static,1) \
3638         magick_number_threads(image,image,image->rows,1)
3639 #endif
3640       for (y=0; y < (ssize_t) image->rows; y++)
3641       {
3642         const int
3643           id = GetOpenMPThreadId();
3644 
3645         register float
3646           *magick_restrict p,
3647           *magick_restrict q;
3648 
3649         register ssize_t
3650           x;
3651 
3652         p=kernel+id*image->columns;
3653         q=pixels+y*image->columns;
3654         HatTransform(q+high_pass,1,image->columns,(size_t) (1UL << level),p);
3655         q+=low_pass;
3656         for (x=0; x < (ssize_t) image->columns; x++)
3657           *q++=(*p++);
3658       }
3659 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3660       #pragma omp parallel for schedule(static,1) \
3661         magick_number_threads(image,image,image->columns,1)
3662 #endif
3663       for (x=0; x < (ssize_t) image->columns; x++)
3664       {
3665         const int
3666           id = GetOpenMPThreadId();
3667 
3668         register float
3669           *magick_restrict p,
3670           *magick_restrict q;
3671 
3672         register ssize_t
3673           y;
3674 
3675         p=kernel+id*image->rows;
3676         q=pixels+x+low_pass;
3677         HatTransform(q,image->columns,image->rows,(size_t) (1UL << level),p);
3678         for (y=0; y < (ssize_t) image->rows; y++)
3679         {
3680           *q=(*p++);
3681           q+=image->columns;
3682         }
3683       }
3684       /*
3685         To threshold, each coefficient is compared to a threshold value and
3686         attenuated / shrunk by some factor.
3687       */
3688       magnitude=threshold*noise_levels[level];
3689       for (i=0; i < (ssize_t) number_pixels; ++i)
3690       {
3691         pixels[high_pass+i]-=pixels[low_pass+i];
3692         if (pixels[high_pass+i] < -magnitude)
3693           pixels[high_pass+i]+=magnitude-softness*magnitude;
3694         else
3695           if (pixels[high_pass+i] > magnitude)
3696             pixels[high_pass+i]-=magnitude-softness*magnitude;
3697           else
3698             pixels[high_pass+i]*=softness;
3699         if (high_pass != 0)
3700           pixels[i]+=pixels[high_pass+i];
3701       }
3702       high_pass=low_pass;
3703     }
3704     /*
3705       Reconstruct image from the thresholded wavelet kernel.
3706     */
3707     i=0;
3708     for (y=0; y < (ssize_t) image->rows; y++)
3709     {
3710       MagickBooleanType
3711         sync;
3712 
3713       register Quantum
3714         *magick_restrict q;
3715 
3716       register ssize_t
3717         x;
3718 
3719       ssize_t
3720         offset;
3721 
3722       q=GetCacheViewAuthenticPixels(noise_view,0,y,noise_image->columns,1,
3723         exception);
3724       if (q == (Quantum *) NULL)
3725         {
3726           status=MagickFalse;
3727           break;
3728         }
3729       offset=GetPixelChannelOffset(noise_image,pixel_channel);
3730       for (x=0; x < (ssize_t) image->columns; x++)
3731       {
3732         MagickRealType
3733           pixel;
3734 
3735         pixel=(MagickRealType) pixels[i]+pixels[low_pass+i];
3736         q[offset]=ClampToQuantum(pixel);
3737         i++;
3738         q+=GetPixelChannels(noise_image);
3739       }
3740       sync=SyncCacheViewAuthenticPixels(noise_view,exception);
3741       if (sync == MagickFalse)
3742         status=MagickFalse;
3743     }
3744     if (image->progress_monitor != (MagickProgressMonitor) NULL)
3745       {
3746         MagickBooleanType
3747           proceed;
3748 
3749         proceed=SetImageProgress(image,AddNoiseImageTag,(MagickOffsetType)
3750           channel,GetPixelChannels(image));
3751         if (proceed == MagickFalse)
3752           status=MagickFalse;
3753       }
3754   }
3755   noise_view=DestroyCacheView(noise_view);
3756   image_view=DestroyCacheView(image_view);
3757   kernel=(float *) RelinquishMagickMemory(kernel);
3758   pixels_info=RelinquishVirtualMemory(pixels_info);
3759   if (status == MagickFalse)
3760     noise_image=DestroyImage(noise_image);
3761   return(noise_image);
3762 }
3763