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