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