MagickCore  7.1.2-29
Convert, Edit, Or Compose Bitmap Images
image.c
1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 % %
4 % %
5 % %
6 % IIIII M M AAA GGGG EEEEE %
7 % I MM MM A A G E %
8 % I M M M AAAAA G GG EEE %
9 % I M M A A G G E %
10 % IIIII M M A A GGGG EEEEE %
11 % %
12 % %
13 % MagickCore Image Methods %
14 % %
15 % Software Design %
16 % Cristy %
17 % July 1992 %
18 % %
19 % %
20 % Copyright @ 1999 ImageMagick Studio LLC, a non-profit organization %
21 % dedicated to making software imaging solutions freely available. %
22 % %
23 % You may not use this file except in compliance with the License. You may %
24 % obtain a copy of the License at %
25 % %
26 % https://imagemagick.org/license/ %
27 % %
28 % Unless required by applicable law or agreed to in writing, software %
29 % distributed under the License is distributed on an "AS IS" BASIS, %
30 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31 % See the License for the specific language governing permissions and %
32 % limitations under the License. %
33 % %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35 %
36 %
37 %
38 */
39 ␌
40 /*
41  Include declarations.
42 */
43 #include "MagickCore/studio.h"
44 #include "MagickCore/animate.h"
45 #include "MagickCore/artifact.h"
46 #include "MagickCore/attribute.h"
47 #include "MagickCore/blob.h"
48 #include "MagickCore/blob-private.h"
49 #include "MagickCore/cache.h"
50 #include "MagickCore/cache-private.h"
51 #include "MagickCore/cache-view.h"
52 #include "MagickCore/channel.h"
53 #include "MagickCore/client.h"
54 #include "MagickCore/color.h"
55 #include "MagickCore/color-private.h"
56 #include "MagickCore/colormap.h"
57 #include "MagickCore/colorspace.h"
58 #include "MagickCore/colorspace-private.h"
59 #include "MagickCore/composite.h"
60 #include "MagickCore/composite-private.h"
61 #include "MagickCore/compress.h"
62 #include "MagickCore/constitute.h"
63 #include "MagickCore/delegate.h"
64 #include "MagickCore/display.h"
65 #include "MagickCore/draw.h"
66 #include "MagickCore/enhance.h"
67 #include "MagickCore/exception.h"
68 #include "MagickCore/exception-private.h"
69 #include "MagickCore/gem.h"
70 #include "MagickCore/geometry.h"
71 #include "MagickCore/histogram.h"
72 #include "MagickCore/image-private.h"
73 #include "MagickCore/list.h"
74 #include "MagickCore/magic.h"
75 #include "MagickCore/magick.h"
76 #include "MagickCore/magick-private.h"
77 #include "MagickCore/memory_.h"
78 #include "MagickCore/memory-private.h"
79 #include "MagickCore/module.h"
80 #include "MagickCore/monitor.h"
81 #include "MagickCore/monitor-private.h"
82 #include "MagickCore/option.h"
83 #include "MagickCore/paint.h"
84 #include "MagickCore/pixel-accessor.h"
85 #include "MagickCore/profile.h"
86 #include "MagickCore/property.h"
87 #include "MagickCore/quantize.h"
88 #include "MagickCore/random_.h"
89 #include "MagickCore/registry.h"
90 #include "MagickCore/resource_.h"
91 #include "MagickCore/segment.h"
92 #include "MagickCore/semaphore.h"
93 #include "MagickCore/signature-private.h"
94 #include "MagickCore/statistic.h"
95 #include "MagickCore/string_.h"
96 #include "MagickCore/string-private.h"
97 #include "MagickCore/thread-private.h"
98 #include "MagickCore/threshold.h"
99 #include "MagickCore/timer.h"
100 #include "MagickCore/timer-private.h"
101 #include "MagickCore/token.h"
102 #include "MagickCore/token-private.h"
103 #include "MagickCore/utility.h"
104 #include "MagickCore/utility-private.h"
105 #include "MagickCore/version.h"
106 #include "MagickCore/xwindow-private.h"
107 ␌
108 /*
109 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
110 % %
111 % %
112 % %
113 % A c q u i r e I m a g e %
114 % %
115 % %
116 % %
117 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
118 %
119 % AcquireImage() returns a pointer to an image structure initialized to
120 % default values.
121 %
122 % The format of the AcquireImage method is:
123 %
124 % Image *AcquireImage(const ImageInfo *image_info,ExceptionInfo *exception)
125 %
126 % A description of each parameter follows:
127 %
128 % o image_info: Many of the image default values are set from this
129 % structure. For example, filename, compression, depth, background color,
130 % and others.
131 %
132 % o exception: return any errors or warnings in this structure.
133 %
134 */
135 MagickExport Image *AcquireImage(const ImageInfo *image_info,
136  ExceptionInfo *exception)
137 {
138  const char
139  *option;
140 
141  Image
142  *image;
143 
144  MagickSizeType
145  time_limit;
146 
147  MagickStatusType
148  flags;
149 
150  /*
151  Allocate image structure.
152  */
153  if (IsEventLogging() != MagickFalse)
154  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
155  image=(Image *) AcquireCriticalMemory(sizeof(*image));
156  (void) memset(image,0,sizeof(*image));
157  /*
158  Initialize Image structure.
159  */
160  (void) CopyMagickString(image->magick,"MIFF",MagickPathExtent);
161  image->storage_class=DirectClass;
162  image->depth=MAGICKCORE_QUANTUM_DEPTH;
163  image->colorspace=sRGBColorspace;
164  image->rendering_intent=PerceptualIntent;
165  image->gamma=1.000/2.200;
166  image->chromaticity.red_primary.x=0.6400;
167  image->chromaticity.red_primary.y=0.3300;
168  image->chromaticity.red_primary.z=0.0300;
169  image->chromaticity.green_primary.x=0.3000;
170  image->chromaticity.green_primary.y=0.6000;
171  image->chromaticity.green_primary.z=0.1000;
172  image->chromaticity.blue_primary.x=0.1500;
173  image->chromaticity.blue_primary.y=0.0600;
174  image->chromaticity.blue_primary.z=0.7900;
175  image->chromaticity.white_point.x=0.3127;
176  image->chromaticity.white_point.y=0.3290;
177  image->chromaticity.white_point.z=0.3583;
178  image->interlace=NoInterlace;
179  image->ticks_per_second=UndefinedTicksPerSecond;
180  image->compose=OverCompositeOp;
181  GetPixelInfoRGBA(BackgroundColorRGBA,&image->background_color);
182  GetPixelInfoRGBA(BorderColorRGBA,&image->border_color);
183  GetPixelInfoRGBA(MatteColorRGBA,&image->matte_color);
184  GetPixelInfoRGBA(TransparentColorRGBA,&image->transparent_color);
185  GetTimerInfo(&image->timer);
186  image->cache=AcquirePixelCache(0);
187  image->channel_mask=AllChannels;
188  image->channel_map=AcquirePixelChannelMap();
189  image->blob=CloneBlobInfo((BlobInfo *) NULL);
190 #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
191  image->timestamp=0; /* Deterministic for fuzzing */
192 #else
193  image->timestamp=time((time_t *) NULL);
194 #endif
195  time_limit=GetMagickResourceLimit(TimeResource);
196  if (time_limit != MagickResourceInfinity)
197  image->ttl=image->timestamp+(time_t) time_limit;
198  image->debug=(GetLogEventMask() & (ImageEvent | TransformEvent | CoderEvent))
199  != 0 ? MagickTrue : MagickFalse;
200  image->reference_count=1;
201  image->semaphore=AcquireSemaphoreInfo();
202  image->signature=MagickCoreSignature;
203  if (image_info == (ImageInfo *) NULL)
204  return(image);
205  /*
206  Transfer image info.
207  */
208  SetBlobExempt(image,image_info->file != (FILE *) NULL ? MagickTrue :
209  MagickFalse);
210  (void) CopyMagickString(image->filename,image_info->filename,
211  MagickPathExtent);
212  (void) CopyMagickString(image->magick_filename,image_info->filename,
213  MagickPathExtent);
214  (void) CopyMagickString(image->magick,image_info->magick,MagickPathExtent);
215  if (image_info->size != (char *) NULL)
216  {
217  (void) ParseAbsoluteGeometry(image_info->size,&image->extract_info);
218  image->columns=image->extract_info.width;
219  image->rows=image->extract_info.height;
220  image->offset=image->extract_info.x;
221  image->extract_info.x=0;
222  image->extract_info.y=0;
223  }
224  if (image_info->extract != (char *) NULL)
225  {
227  geometry;
228 
229  (void) memset(&geometry,0,sizeof(geometry));
230  flags=ParseAbsoluteGeometry(image_info->extract,&geometry);
231  if (((flags & XValue) != 0) || ((flags & YValue) != 0))
232  {
233  image->extract_info=geometry;
234  Swap(image->columns,image->extract_info.width);
235  Swap(image->rows,image->extract_info.height);
236  }
237  }
238  image->compression=image_info->compression;
239  image->quality=image_info->quality;
240  image->endian=image_info->endian;
241  image->interlace=image_info->interlace;
242  image->units=image_info->units;
243  if (image_info->density != (char *) NULL)
244  {
246  geometry_info;
247 
248  flags=ParseGeometry(image_info->density,&geometry_info);
249  if ((flags & RhoValue) != 0)
250  image->resolution.x=geometry_info.rho;
251  image->resolution.y=image->resolution.x;
252  if ((flags & SigmaValue) != 0)
253  image->resolution.y=geometry_info.sigma;
254  }
255  if (image_info->page != (char *) NULL)
256  {
257  char
258  *geometry;
259 
260  image->page=image->extract_info;
261  geometry=GetPageGeometry(image_info->page);
262  (void) ParseAbsoluteGeometry(geometry,&image->page);
263  geometry=DestroyString(geometry);
264  }
265  if (image_info->depth != 0)
266  image->depth=image_info->depth;
267  image->dither=image_info->dither;
268  image->matte_color=image_info->matte_color;
269  image->background_color=image_info->background_color;
270  image->border_color=image_info->border_color;
271  image->transparent_color=image_info->transparent_color;
272  image->ping=image_info->ping;
273  image->progress_monitor=image_info->progress_monitor;
274  image->client_data=image_info->client_data;
275  if (image_info->cache != (void *) NULL)
276  ClonePixelCacheMethods(image->cache,image_info->cache);
277  /*
278  Set all global options that map to per-image settings.
279  */
280  (void) SyncImageSettings(image_info,image,exception);
281  /*
282  Global options that are only set for new images.
283  */
284  option=GetImageOption(image_info,"delay");
285  if (option != (const char *) NULL)
286  {
288  geometry_info;
289 
290  flags=ParseGeometry(option,&geometry_info);
291  if ((flags & GreaterValue) != 0)
292  {
293  if ((double) image->delay > floor(geometry_info.rho+0.5))
294  image->delay=(size_t) CastDoubleToSsizeT(floor(geometry_info.rho+
295  0.5));
296  }
297  else
298  if ((flags & LessValue) != 0)
299  {
300  if ((double) image->delay < floor(geometry_info.rho+0.5))
301  image->ticks_per_second=CastDoubleToSsizeT(floor(
302  geometry_info.sigma+0.5));
303  }
304  else
305  image->delay=(size_t) CastDoubleToSsizeT(floor(geometry_info.rho+
306  0.5));
307  if ((flags & SigmaValue) != 0)
308  image->ticks_per_second=CastDoubleToSsizeT(floor(geometry_info.sigma+
309  0.5));
310  }
311  option=GetImageOption(image_info,"dispose");
312  if (option != (const char *) NULL)
313  image->dispose=(DisposeType) ParseCommandOption(MagickDisposeOptions,
314  MagickFalse,option);
315  return(image);
316 }
317 ␌
318 /*
319 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
320 % %
321 % %
322 % %
323 % A c q u i r e I m a g e I n f o %
324 % %
325 % %
326 % %
327 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
328 %
329 % AcquireImageInfo() allocates the ImageInfo structure.
330 %
331 % The format of the AcquireImageInfo method is:
332 %
333 % ImageInfo *AcquireImageInfo(void)
334 %
335 */
336 MagickExport ImageInfo *AcquireImageInfo(void)
337 {
338  ImageInfo
339  *image_info;
340 
341  image_info=(ImageInfo *) AcquireCriticalMemory(sizeof(*image_info));
342  GetImageInfo(image_info);
343  return(image_info);
344 }
345 ␌
346 /*
347 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
348 % %
349 % %
350 % %
351 % A c q u i r e N e x t I m a g e %
352 % %
353 % %
354 % %
355 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
356 %
357 % AcquireNextImage() initializes the next image in a sequence to
358 % default values. The next member of image points to the newly allocated
359 % image. If there is a memory shortage, next is assigned NULL.
360 %
361 % The format of the AcquireNextImage method is:
362 %
363 % void AcquireNextImage(const ImageInfo *image_info,Image *image,
364 % ExceptionInfo *exception)
365 %
366 % A description of each parameter follows:
367 %
368 % o image_info: Many of the image default values are set from this
369 % structure. For example, filename, compression, depth, background color,
370 % and others.
371 %
372 % o image: the image.
373 %
374 % o exception: return any errors or warnings in this structure.
375 %
376 */
377 MagickExport void AcquireNextImage(const ImageInfo *image_info,Image *image,
378  ExceptionInfo *exception)
379 {
380  /*
381  Allocate image structure.
382  */
383  assert(image != (Image *) NULL);
384  assert(image->signature == MagickCoreSignature);
385  if (IsEventLogging() != MagickFalse)
386  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
387  image->next=AcquireImage(image_info,exception);
388  if (GetNextImageInList(image) == (Image *) NULL)
389  return;
390  (void) CopyMagickString(GetNextImageInList(image)->filename,image->filename,
391  MagickPathExtent);
392  if (image_info != (ImageInfo *) NULL)
393  (void) CopyMagickString(GetNextImageInList(image)->filename,
394  image_info->filename,MagickPathExtent);
395  DestroyBlob(GetNextImageInList(image));
396  image->next->blob=ReferenceBlob(image->blob);
397  image->next->endian=image->endian;
398  image->next->scene=image->scene+1;
399  image->next->previous=image;
400 }
401 ␌
402 /*
403 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
404 % %
405 % %
406 % %
407 % A p p e n d I m a g e s %
408 % %
409 % %
410 % %
411 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
412 %
413 % AppendImages() takes all images from the current image pointer to the end
414 % of the image list and appends them to each other top-to-bottom if the
415 % stack parameter is true, otherwise left-to-right.
416 %
417 % The current gravity setting effects how the image is justified in the
418 % final image.
419 %
420 % The format of the AppendImages method is:
421 %
422 % Image *AppendImages(const Image *images,const MagickBooleanType stack,
423 % ExceptionInfo *exception)
424 %
425 % A description of each parameter follows:
426 %
427 % o images: the image sequence.
428 %
429 % o stack: A value other than 0 stacks the images top-to-bottom.
430 %
431 % o exception: return any errors or warnings in this structure.
432 %
433 */
434 MagickExport Image *AppendImages(const Image *images,
435  const MagickBooleanType stack,ExceptionInfo *exception)
436 {
437 #define AppendImageTag "Append/Image"
438 
439  CacheView
440  *append_view;
441 
442  Image
443  *append_image;
444 
445  ImageType
446  image_type;
447 
448  MagickBooleanType
449  homogeneous_colorspace,
450  status;
451 
452  MagickOffsetType
453  n;
454 
455  PixelTrait
456  alpha_trait;
457 
459  geometry;
460 
461  const Image
462  *next;
463 
464  size_t
465  depth,
466  height,
467  number_images,
468  width;
469 
470  ssize_t
471  x_offset,
472  y,
473  y_offset;
474 
475  /*
476  Compute maximum area of appended area.
477  */
478  assert(images != (Image *) NULL);
479  assert(images->signature == MagickCoreSignature);
480  assert(exception != (ExceptionInfo *) NULL);
481  assert(exception->signature == MagickCoreSignature);
482  if (IsEventLogging() != MagickFalse)
483  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
484  alpha_trait=images->alpha_trait;
485  number_images=1;
486  width=images->columns;
487  height=images->rows;
488  depth=images->depth;
489  image_type=images->type;
490  homogeneous_colorspace=MagickTrue;
491  next=GetNextImageInList(images);
492  for ( ; next != (Image *) NULL; next=GetNextImageInList(next))
493  {
494  if (next->depth > depth)
495  depth=next->depth;
496  if (next->type != images->type)
497  image_type=UndefinedType;
498  if (next->colorspace != images->colorspace)
499  homogeneous_colorspace=MagickFalse;
500  if (next->alpha_trait != UndefinedPixelTrait)
501  alpha_trait=BlendPixelTrait;
502  number_images++;
503  if (stack != MagickFalse)
504  {
505  if (next->columns > width)
506  width=next->columns;
507  height+=next->rows;
508  continue;
509  }
510  width+=next->columns;
511  if (next->rows > height)
512  height=next->rows;
513  }
514  /*
515  Append images.
516  */
517  append_image=CloneImage(images,width,height,MagickTrue,exception);
518  if (append_image == (Image *) NULL)
519  return((Image *) NULL);
520  if (image_type != BilevelType)
521  {
522  if (SetImageStorageClass(append_image,DirectClass,exception) == MagickFalse)
523  {
524  append_image=DestroyImage(append_image);
525  return((Image *) NULL);
526  }
527  if (homogeneous_colorspace == MagickFalse)
528  (void) SetImageColorspace(append_image,sRGBColorspace,exception);
529  }
530  append_image->depth=depth;
531  append_image->alpha_trait=alpha_trait;
532  append_image->page=images->page;
533  (void) SetImageBackgroundColor(append_image,exception);
534  status=MagickTrue;
535  x_offset=0;
536  y_offset=0;
537  next=images;
538  append_view=AcquireAuthenticCacheView(append_image,exception);
539  for (n=0; n < (MagickOffsetType) number_images; n++)
540  {
541  CacheView
542  *image_view;
543 
544  MagickBooleanType
545  proceed;
546 
547  SetGeometry(append_image,&geometry);
548  GravityAdjustGeometry(next->columns,next->rows,next->gravity,&geometry);
549  if (stack != MagickFalse)
550  x_offset-=geometry.x;
551  else
552  y_offset-=geometry.y;
553  image_view=AcquireVirtualCacheView(next,exception);
554 #if defined(MAGICKCORE_OPENMP_SUPPORT)
555  #pragma omp parallel for schedule(static) shared(status) \
556  magick_number_threads(next,next,next->rows,2)
557 #endif
558  for (y=0; y < (ssize_t) next->rows; y++)
559  {
560  MagickBooleanType
561  sync;
562 
563  PixelInfo
564  pixel;
565 
566  const Quantum
567  *magick_restrict p;
568 
569  Quantum
570  *magick_restrict q;
571 
572  ssize_t
573  x;
574 
575  if (status == MagickFalse)
576  continue;
577  p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
578  q=QueueCacheViewAuthenticPixels(append_view,x_offset,y+y_offset,
579  next->columns,1,exception);
580  if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
581  {
582  status=MagickFalse;
583  continue;
584  }
585  GetPixelInfo(next,&pixel);
586  for (x=0; x < (ssize_t) next->columns; x++)
587  {
588  GetPixelInfoPixel(next,p,&pixel);
589  SetPixelViaPixelInfo(append_image,&pixel,q);
590  p+=(ptrdiff_t) GetPixelChannels(next);
591  q+=(ptrdiff_t) GetPixelChannels(append_image);
592  }
593  sync=SyncCacheViewAuthenticPixels(append_view,exception);
594  if (sync == MagickFalse)
595  status=MagickFalse;
596  }
597  image_view=DestroyCacheView(image_view);
598  if (stack == MagickFalse)
599  {
600  x_offset+=(ssize_t) next->columns;
601  y_offset=0;
602  }
603  else
604  {
605  x_offset=0;
606  y_offset+=(ssize_t) next->rows;
607  }
608  proceed=SetImageProgress(append_image,AppendImageTag,n,number_images);
609  if (proceed == MagickFalse)
610  break;
611  next=GetNextImageInList(next);
612  }
613  append_view=DestroyCacheView(append_view);
614  if (status == MagickFalse)
615  append_image=DestroyImage(append_image);
616  return(append_image);
617 }
618 ␌
619 /*
620 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
621 % %
622 % %
623 % %
624 % C a t c h I m a g e E x c e p t i o n %
625 % %
626 % %
627 % %
628 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
629 %
630 % CatchImageException() returns if no exceptions are found in the image
631 % sequence, otherwise it determines the most severe exception and reports
632 % it as a warning or error depending on the severity.
633 %
634 % The format of the CatchImageException method is:
635 %
636 % ExceptionType CatchImageException(Image *image)
637 %
638 % A description of each parameter follows:
639 %
640 % o image: An image sequence.
641 %
642 */
643 MagickExport ExceptionType CatchImageException(Image *image)
644 {
646  *exception;
647 
648  ExceptionType
649  severity;
650 
651  assert(image != (const Image *) NULL);
652  assert(image->signature == MagickCoreSignature);
653  if (IsEventLogging() != MagickFalse)
654  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
655  exception=AcquireExceptionInfo();
656  CatchException(exception);
657  severity=exception->severity;
658  exception=DestroyExceptionInfo(exception);
659  return(severity);
660 }
661 ␌
662 /*
663 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
664 % %
665 % %
666 % %
667 % C l i p I m a g e P a t h %
668 % %
669 % %
670 % %
671 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
672 %
673 % ClipImagePath() sets the image clip mask based any clipping path information
674 % if it exists.
675 %
676 % The format of the ClipImagePath method is:
677 %
678 % MagickBooleanType ClipImagePath(Image *image,const char *pathname,
679 % const MagickBooleanType inside,ExceptionInfo *exception)
680 %
681 % A description of each parameter follows:
682 %
683 % o image: the image.
684 %
685 % o pathname: name of clipping path resource. If name is preceded by #, use
686 % clipping path numbered by name.
687 %
688 % o inside: if non-zero, later operations take effect inside clipping path.
689 % Otherwise later operations take effect outside clipping path.
690 %
691 % o exception: return any errors or warnings in this structure.
692 %
693 */
694 
695 MagickExport MagickBooleanType ClipImage(Image *image,ExceptionInfo *exception)
696 {
697  return(ClipImagePath(image,"#1",MagickTrue,exception));
698 }
699 
700 MagickExport MagickBooleanType ClipImagePath(Image *image,const char *pathname,
701  const MagickBooleanType inside,ExceptionInfo *exception)
702 {
703 #define ClipImagePathTag "ClipPath/Image"
704 
705  char
706  *property,
707  *sanitized_pathname;
708 
709  const char
710  *value;
711 
712  Image
713  *clip_mask;
714 
715  ImageInfo
716  *image_info;
717 
718  assert(image != (const Image *) NULL);
719  assert(image->signature == MagickCoreSignature);
720  assert(pathname != NULL);
721  if (IsEventLogging() != MagickFalse)
722  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
723  property=AcquireString(pathname);
724  (void) FormatLocaleString(property,MagickPathExtent,"8BIM:1999,2998:%s",
725  pathname);
726  value=GetImageProperty(image,property,exception);
727  property=DestroyString(property);
728  if (value == (const char *) NULL)
729  {
730  ThrowFileException(exception,OptionError,"NoClipPathDefined",
731  image->filename);
732  return(MagickFalse);
733  }
734  image_info=AcquireImageInfo();
735  (void) CopyMagickString(image_info->filename,image->filename,
736  MagickPathExtent);
737  (void) ConcatenateMagickString(image_info->filename,"_",MagickPathExtent);
738  sanitized_pathname=SanitizeString(pathname);
739  (void) ConcatenateMagickString(image_info->filename,sanitized_pathname,
740  MagickPathExtent);
741  sanitized_pathname=DestroyString(sanitized_pathname);
742  clip_mask=BlobToImage(image_info,value,strlen(value),exception);
743  image_info=DestroyImageInfo(image_info);
744  if (clip_mask == (Image *) NULL)
745  return(MagickFalse);
746  if (clip_mask->storage_class == PseudoClass)
747  {
748  (void) SyncImage(clip_mask,exception);
749  if (SetImageStorageClass(clip_mask,DirectClass,exception) == MagickFalse)
750  return(MagickFalse);
751  }
752  if (inside != MagickFalse)
753  (void) NegateImage(clip_mask,MagickFalse,exception);
754  (void) FormatLocaleString(clip_mask->magick_filename,MagickPathExtent,
755  "8BIM:1999,2998:%s\nPS",pathname);
756  (void) SetImageMask(image,WritePixelMask,clip_mask,exception);
757  clip_mask=DestroyImage(clip_mask);
758  return(MagickTrue);
759 }
760 ␌
761 /*
762 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
763 % %
764 % %
765 % %
766 % C l o n e I m a g e %
767 % %
768 % %
769 % %
770 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
771 %
772 % CloneImage() copies an image and returns the copy as a new image object.
773 %
774 % If the specified columns and rows is 0, an exact copy of the image is
775 % returned, otherwise the pixel data is undefined and must be initialized
776 % with the QueueAuthenticPixels() and SyncAuthenticPixels() methods. On
777 % failure, a NULL image is returned and exception describes the reason for the
778 % failure.
779 %
780 % The format of the CloneImage method is:
781 %
782 % Image *CloneImage(const Image *image,const size_t columns,
783 % const size_t rows,const MagickBooleanType orphan,
784 % ExceptionInfo *exception)
785 %
786 % A description of each parameter follows:
787 %
788 % o image: the image.
789 %
790 % o columns: the number of columns in the cloned image.
791 %
792 % o rows: the number of rows in the cloned image.
793 %
794 % o detach: With a value other than 0, the cloned image is detached from
795 % its parent I/O stream.
796 %
797 % o exception: return any errors or warnings in this structure.
798 %
799 */
800 MagickExport Image *CloneImage(const Image *image,const size_t columns,
801  const size_t rows,const MagickBooleanType detach,ExceptionInfo *exception)
802 {
803  double
804  scale_x,
805  scale_y;
806 
807  Image
808  *clone_image;
809 
810  size_t
811  length;
812 
813  /*
814  Clone the image.
815  */
816  assert(image != (const Image *) NULL);
817  assert(image->signature == MagickCoreSignature);
818  assert(exception != (ExceptionInfo *) NULL);
819  assert(exception->signature == MagickCoreSignature);
820  if (IsEventLogging() != MagickFalse)
821  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
822  if ((image->columns == 0) || (image->rows == 0))
823  {
824  (void) ThrowMagickException(exception,GetMagickModule(),CorruptImageError,
825  "NegativeOrZeroImageSize","`%s'",image->filename);
826  return((Image *) NULL);
827  }
828  clone_image=(Image *) AcquireCriticalMemory(sizeof(*clone_image));
829  (void) memset(clone_image,0,sizeof(*clone_image));
830  clone_image->signature=MagickCoreSignature;
831  clone_image->storage_class=image->storage_class;
832  clone_image->number_channels=image->number_channels;
833  clone_image->number_meta_channels=image->number_meta_channels;
834  clone_image->metacontent_extent=image->metacontent_extent;
835  clone_image->colorspace=image->colorspace;
836  clone_image->alpha_trait=image->alpha_trait;
837  clone_image->channels=image->channels;
838  clone_image->mask_trait=image->mask_trait;
839  clone_image->columns=image->columns;
840  clone_image->rows=image->rows;
841  clone_image->dither=image->dither;
842  clone_image->image_info=CloneImageInfo(image->image_info);
843  (void) CloneImageProfiles(clone_image,image);
844  (void) CloneImageProperties(clone_image,image);
845  (void) CloneImageArtifacts(clone_image,image);
846  GetTimerInfo(&clone_image->timer);
847  if (image->ascii85 != (void *) NULL)
848  Ascii85Initialize(clone_image);
849  clone_image->extent=image->extent;
850  clone_image->magick_columns=image->magick_columns;
851  clone_image->magick_rows=image->magick_rows;
852  clone_image->type=image->type;
853  clone_image->channel_mask=image->channel_mask;
854  clone_image->channel_map=ClonePixelChannelMap(image->channel_map);
855  (void) CopyMagickString(clone_image->magick_filename,image->magick_filename,
856  MagickPathExtent);
857  (void) CopyMagickString(clone_image->magick,image->magick,MagickPathExtent);
858  (void) CopyMagickString(clone_image->filename,image->filename,
859  MagickPathExtent);
860  clone_image->progress_monitor=image->progress_monitor;
861  clone_image->client_data=image->client_data;
862  clone_image->reference_count=1;
863  clone_image->next=image->next;
864  clone_image->previous=image->previous;
865  clone_image->list=NewImageList();
866  if (detach == MagickFalse)
867  clone_image->blob=ReferenceBlob(image->blob);
868  else
869  {
870  clone_image->next=NewImageList();
871  clone_image->previous=NewImageList();
872  clone_image->blob=CloneBlobInfo((BlobInfo *) NULL);
873  }
874  clone_image->ping=image->ping;
875  clone_image->timestamp=image->timestamp;
876  clone_image->ttl=image->ttl;
877  clone_image->debug=image->debug;
878  clone_image->semaphore=AcquireSemaphoreInfo();
879  if (image->colormap != (PixelInfo *) NULL)
880  {
881  /*
882  Allocate and copy the image colormap.
883  */
884  clone_image->colors=image->colors;
885  length=(size_t) image->colors;
886  clone_image->colormap=(PixelInfo *) AcquireQuantumMemory(length+1,
887  sizeof(*clone_image->colormap));
888  if (clone_image->colormap == (PixelInfo *) NULL)
889  {
890  clone_image=DestroyImage(clone_image);
891  ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
892  }
893  (void) memcpy(clone_image->colormap,image->colormap,length*
894  sizeof(*clone_image->colormap));
895  }
896  if ((columns == 0) || (rows == 0))
897  {
898  if (image->montage != (char *) NULL)
899  (void) CloneString(&clone_image->montage,image->montage);
900  if (image->directory != (char *) NULL)
901  (void) CloneString(&clone_image->directory,image->directory);
902  clone_image->cache=ReferencePixelCache(image->cache);
903  return(clone_image);
904  }
905  scale_x=1.0;
906  scale_y=1.0;
907  if (image->columns != 0)
908  scale_x=(double) columns/(double) image->columns;
909  if (image->rows != 0)
910  scale_y=(double) rows/(double) image->rows;
911  clone_image->page.width=(size_t) CastDoubleToSsizeT(floor(scale_x*
912  image->page.width+0.5));
913  clone_image->page.height=(size_t) CastDoubleToSsizeT(floor(scale_y*
914  image->page.height+0.5));
915  if (MagickAbsoluteValue(scale_x-scale_y) < 2.0)
916  scale_x=scale_y=MagickMin(scale_x,scale_y);
917  clone_image->page.x=CastDoubleToSsizeT(ceil(scale_x*image->page.x-0.5));
918  clone_image->tile_offset.x=CastDoubleToSsizeT(ceil(scale_x*
919  image->tile_offset.x-0.5));
920  clone_image->page.y=CastDoubleToSsizeT(ceil(scale_y*image->page.y-0.5));
921  clone_image->tile_offset.y=CastDoubleToSsizeT(ceil(scale_y*
922  image->tile_offset.y-0.5));
923  clone_image->cache=ClonePixelCache(image->cache);
924  if (SetImageExtent(clone_image,columns,rows,exception) == MagickFalse)
925  clone_image=DestroyImage(clone_image);
926  return(clone_image);
927 }
928 ␌
929 /*
930 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
931 % %
932 % %
933 % %
934 % C l o n e I m a g e I n f o %
935 % %
936 % %
937 % %
938 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
939 %
940 % CloneImageInfo() makes a copy of the given image info structure. If
941 % NULL is specified, a new image info structure is created initialized to
942 % default values.
943 %
944 % The format of the CloneImageInfo method is:
945 %
946 % ImageInfo *CloneImageInfo(const ImageInfo *image_info)
947 %
948 % A description of each parameter follows:
949 %
950 % o image_info: the image info.
951 %
952 */
953 MagickExport ImageInfo *CloneImageInfo(const ImageInfo *image_info)
954 {
955  ImageInfo
956  *clone_info;
957 
958  clone_info=AcquireImageInfo();
959  if (image_info == (ImageInfo *) NULL)
960  return(clone_info);
961  clone_info->compression=image_info->compression;
962  clone_info->temporary=image_info->temporary;
963  clone_info->adjoin=image_info->adjoin;
964  clone_info->antialias=image_info->antialias;
965  clone_info->scene=image_info->scene;
966  clone_info->number_scenes=image_info->number_scenes;
967  clone_info->depth=image_info->depth;
968  if (image_info->size != (char *) NULL)
969  (void) CloneString(&clone_info->size,image_info->size);
970  if (image_info->extract != (char *) NULL)
971  (void) CloneString(&clone_info->extract,image_info->extract);
972  if (image_info->scenes != (char *) NULL)
973  (void) CloneString(&clone_info->scenes,image_info->scenes);
974  if (image_info->page != (char *) NULL)
975  (void) CloneString(&clone_info->page,image_info->page);
976  clone_info->interlace=image_info->interlace;
977  clone_info->endian=image_info->endian;
978  clone_info->units=image_info->units;
979  clone_info->quality=image_info->quality;
980  if (image_info->sampling_factor != (char *) NULL)
981  (void) CloneString(&clone_info->sampling_factor,
982  image_info->sampling_factor);
983  if (image_info->server_name != (char *) NULL)
984  (void) CloneString(&clone_info->server_name,image_info->server_name);
985  if (image_info->font != (char *) NULL)
986  (void) CloneString(&clone_info->font,image_info->font);
987  if (image_info->texture != (char *) NULL)
988  (void) CloneString(&clone_info->texture,image_info->texture);
989  if (image_info->density != (char *) NULL)
990  (void) CloneString(&clone_info->density,image_info->density);
991  clone_info->pointsize=image_info->pointsize;
992  clone_info->fuzz=image_info->fuzz;
993  clone_info->matte_color=image_info->matte_color;
994  clone_info->background_color=image_info->background_color;
995  clone_info->border_color=image_info->border_color;
996  clone_info->transparent_color=image_info->transparent_color;
997  clone_info->dither=image_info->dither;
998  clone_info->monochrome=image_info->monochrome;
999  clone_info->colorspace=image_info->colorspace;
1000  clone_info->type=image_info->type;
1001  clone_info->orientation=image_info->orientation;
1002  clone_info->ping=image_info->ping;
1003  clone_info->verbose=image_info->verbose;
1004  clone_info->progress_monitor=image_info->progress_monitor;
1005  clone_info->client_data=image_info->client_data;
1006  clone_info->cache=image_info->cache;
1007  if (image_info->cache != (void *) NULL)
1008  clone_info->cache=ReferencePixelCache(image_info->cache);
1009  if (image_info->profile != (void *) NULL)
1010  clone_info->profile=(void *) CloneStringInfo((StringInfo *)
1011  image_info->profile);
1012  SetImageInfoFile(clone_info,image_info->file);
1013  SetImageInfoBlob(clone_info,image_info->blob,image_info->length);
1014  clone_info->stream=image_info->stream;
1015  clone_info->custom_stream=image_info->custom_stream;
1016  (void) CopyMagickString(clone_info->magick,image_info->magick,
1017  MagickPathExtent);
1018  (void) CopyMagickString(clone_info->unique,image_info->unique,
1019  MagickPathExtent);
1020  (void) CopyMagickString(clone_info->filename,image_info->filename,
1021  MagickPathExtent);
1022  clone_info->channel=image_info->channel;
1023  (void) CloneImageOptions(clone_info,image_info);
1024  clone_info->debug=image_info->debug;
1025  clone_info->signature=image_info->signature;
1026  return(clone_info);
1027 }
1028 ␌
1029 /*
1030 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1031 % %
1032 % %
1033 % %
1034 % C o p y I m a g e P i x e l s %
1035 % %
1036 % %
1037 % %
1038 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1039 %
1040 % CopyImagePixels() copies pixels from the source image as defined by the
1041 % geometry the destination image at the specified offset.
1042 %
1043 % The format of the CopyImagePixels method is:
1044 %
1045 % MagickBooleanType CopyImagePixels(Image *image,const Image *source_image,
1046 % const RectangleInfo *geometry,const OffsetInfo *offset,
1047 % ExceptionInfo *exception)
1048 %
1049 % A description of each parameter follows:
1050 %
1051 % o image: the destination image.
1052 %
1053 % o source_image: the source image.
1054 %
1055 % o geometry: define the dimensions of the source pixel rectangle.
1056 %
1057 % o offset: define the offset in the destination image.
1058 %
1059 % o exception: return any errors or warnings in this structure.
1060 %
1061 */
1062 MagickExport MagickBooleanType CopyImagePixels(Image *image,
1063  const Image *source_image,const RectangleInfo *geometry,
1064  const OffsetInfo *offset,ExceptionInfo *exception)
1065 {
1066 #define CopyImageTag "Copy/Image"
1067 
1068  CacheView
1069  *image_view,
1070  *source_view;
1071 
1072  MagickBooleanType
1073  status;
1074 
1075  MagickOffsetType
1076  progress;
1077 
1078  ssize_t
1079  y;
1080 
1081  assert(image != (Image *) NULL);
1082  assert(source_image != (Image *) NULL);
1083  assert(geometry != (RectangleInfo *) NULL);
1084  assert(offset != (OffsetInfo *) NULL);
1085  if (IsEventLogging() != MagickFalse)
1086  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1087  if ((offset->x < 0) || (offset->y < 0) ||
1088  ((offset->x+(ssize_t) geometry->width) > (ssize_t) image->columns) ||
1089  ((offset->y+(ssize_t) geometry->height) > (ssize_t) image->rows))
1090  ThrowBinaryException(OptionError,"GeometryDoesNotContainImage",
1091  image->filename);
1092  if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
1093  return(MagickFalse);
1094  /*
1095  Copy image pixels.
1096  */
1097  status=MagickTrue;
1098  progress=0;
1099  source_view=AcquireVirtualCacheView(source_image,exception);
1100  image_view=AcquireAuthenticCacheView(image,exception);
1101 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1102  #pragma omp parallel for schedule(static) shared(progress,status) \
1103  magick_number_threads(image,source_image,geometry->height,2)
1104 #endif
1105  for (y=0; y < (ssize_t) geometry->height; y++)
1106  {
1107  MagickBooleanType
1108  sync;
1109 
1110  const Quantum
1111  *magick_restrict p;
1112 
1113  ssize_t
1114  x;
1115 
1116  Quantum
1117  *magick_restrict q;
1118 
1119  if (status == MagickFalse)
1120  continue;
1121  p=GetCacheViewVirtualPixels(source_view,geometry->x,y+geometry->y,
1122  geometry->width,1,exception);
1123  q=QueueCacheViewAuthenticPixels(image_view,offset->x,y+offset->y,
1124  geometry->width,1,exception);
1125  if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
1126  {
1127  status=MagickFalse;
1128  continue;
1129  }
1130  for (x=0; x < (ssize_t) geometry->width; x++)
1131  {
1132  ssize_t
1133  i;
1134 
1135  for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1136  {
1137  PixelChannel channel = GetPixelChannelChannel(image,i);
1138  PixelTrait traits = GetPixelChannelTraits(image,channel);
1139  PixelTrait source_traits=GetPixelChannelTraits(source_image,channel);
1140  if ((traits == UndefinedPixelTrait) ||
1141  ((traits & UpdatePixelTrait) == 0) ||
1142  (source_traits == UndefinedPixelTrait))
1143  continue;
1144  SetPixelChannel(image,channel,p[i],q);
1145  }
1146  p+=(ptrdiff_t) GetPixelChannels(source_image);
1147  q+=(ptrdiff_t) GetPixelChannels(image);
1148  }
1149  sync=SyncCacheViewAuthenticPixels(image_view,exception);
1150  if (sync == MagickFalse)
1151  status=MagickFalse;
1152  if (image->progress_monitor != (MagickProgressMonitor) NULL)
1153  {
1154  MagickBooleanType
1155  proceed;
1156 
1157 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1158  #pragma omp atomic
1159 #endif
1160  progress++;
1161  proceed=SetImageProgress(image,CopyImageTag,progress,image->rows);
1162  if (proceed == MagickFalse)
1163  status=MagickFalse;
1164  }
1165  }
1166  source_view=DestroyCacheView(source_view);
1167  image_view=DestroyCacheView(image_view);
1168  return(status);
1169 }
1170 ␌
1171 /*
1172 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1173 % %
1174 % %
1175 % %
1176 % D e s t r o y I m a g e %
1177 % %
1178 % %
1179 % %
1180 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1181 %
1182 % DestroyImage() dereferences an image, deallocating memory associated with
1183 % the image if the reference count becomes zero.
1184 %
1185 % The format of the DestroyImage method is:
1186 %
1187 % Image *DestroyImage(Image *image)
1188 %
1189 % A description of each parameter follows:
1190 %
1191 % o image: the image.
1192 %
1193 */
1194 MagickExport Image *DestroyImage(Image *image)
1195 {
1196  MagickBooleanType
1197  destroy;
1198 
1199  /*
1200  Dereference image.
1201  */
1202  assert(image != (Image *) NULL);
1203  assert(image->signature == MagickCoreSignature);
1204  if (IsEventLogging() != MagickFalse)
1205  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1206  destroy=MagickFalse;
1207  LockSemaphoreInfo(image->semaphore);
1208  image->reference_count--;
1209  if (image->reference_count == 0)
1210  destroy=MagickTrue;
1211  UnlockSemaphoreInfo(image->semaphore);
1212  if (destroy == MagickFalse)
1213  return((Image *) NULL);
1214  /*
1215  Destroy image.
1216  */
1217  DestroyImagePixels(image);
1218  image->channel_map=DestroyPixelChannelMap(image->channel_map);
1219  if (image->montage != (char *) NULL)
1220  image->montage=DestroyString(image->montage);
1221  if (image->directory != (char *) NULL)
1222  image->directory=DestroyString(image->directory);
1223  if (image->colormap != (PixelInfo *) NULL)
1224  image->colormap=(PixelInfo *) RelinquishMagickMemory(image->colormap);
1225  if (image->geometry != (char *) NULL)
1226  image->geometry=DestroyString(image->geometry);
1227  DestroyImageProfiles(image);
1228  DestroyImageProperties(image);
1229  DestroyImageArtifacts(image);
1230  if (image->ascii85 != (Ascii85Info *) NULL)
1231  image->ascii85=(Ascii85Info *) RelinquishMagickMemory(image->ascii85);
1232  if (image->image_info != (ImageInfo *) NULL)
1233  image->image_info=DestroyImageInfo(image->image_info);
1234  DestroyBlob(image);
1235  if (image->semaphore != (SemaphoreInfo *) NULL)
1236  RelinquishSemaphoreInfo(&image->semaphore);
1237  image->signature=(~MagickCoreSignature);
1238  image=(Image *) RelinquishMagickMemory(image);
1239  return(image);
1240 }
1241 ␌
1242 /*
1243 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1244 % %
1245 % %
1246 % %
1247 % D e s t r o y I m a g e I n f o %
1248 % %
1249 % %
1250 % %
1251 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1252 %
1253 % DestroyImageInfo() deallocates memory associated with an ImageInfo
1254 % structure.
1255 %
1256 % The format of the DestroyImageInfo method is:
1257 %
1258 % ImageInfo *DestroyImageInfo(ImageInfo *image_info)
1259 %
1260 % A description of each parameter follows:
1261 %
1262 % o image_info: the image info.
1263 %
1264 */
1265 MagickExport ImageInfo *DestroyImageInfo(ImageInfo *image_info)
1266 {
1267  assert(image_info != (ImageInfo *) NULL);
1268  assert(image_info->signature == MagickCoreSignature);
1269  if (IsEventLogging() != MagickFalse)
1270  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1271  image_info->filename);
1272  if (image_info->size != (char *) NULL)
1273  image_info->size=DestroyString(image_info->size);
1274  if (image_info->extract != (char *) NULL)
1275  image_info->extract=DestroyString(image_info->extract);
1276  if (image_info->scenes != (char *) NULL)
1277  image_info->scenes=DestroyString(image_info->scenes);
1278  if (image_info->page != (char *) NULL)
1279  image_info->page=DestroyString(image_info->page);
1280  if (image_info->sampling_factor != (char *) NULL)
1281  image_info->sampling_factor=DestroyString(
1282  image_info->sampling_factor);
1283  if (image_info->server_name != (char *) NULL)
1284  image_info->server_name=DestroyString(
1285  image_info->server_name);
1286  if (image_info->font != (char *) NULL)
1287  image_info->font=DestroyString(image_info->font);
1288  if (image_info->texture != (char *) NULL)
1289  image_info->texture=DestroyString(image_info->texture);
1290  if (image_info->density != (char *) NULL)
1291  image_info->density=DestroyString(image_info->density);
1292  if (image_info->cache != (void *) NULL)
1293  image_info->cache=DestroyPixelCache(image_info->cache);
1294  if (image_info->profile != (StringInfo *) NULL)
1295  image_info->profile=(void *) DestroyStringInfo((StringInfo *)
1296  image_info->profile);
1297  DestroyImageOptions(image_info);
1298  image_info->signature=(~MagickCoreSignature);
1299  image_info=(ImageInfo *) RelinquishMagickMemory(image_info);
1300  return(image_info);
1301 }
1302 ␌
1303 /*
1304 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1305 % %
1306 % %
1307 % %
1308 + D i s a s s o c i a t e I m a g e S t r e a m %
1309 % %
1310 % %
1311 % %
1312 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1313 %
1314 % DisassociateImageStream() disassociates the image stream. It checks if the
1315 % blob of the specified image is referenced by other images. If the reference
1316 % count is higher then 1 a new blob is assigned to the specified image.
1317 %
1318 % The format of the DisassociateImageStream method is:
1319 %
1320 % void DisassociateImageStream(const Image *image)
1321 %
1322 % A description of each parameter follows:
1323 %
1324 % o image: the image.
1325 %
1326 */
1327 MagickExport void DisassociateImageStream(Image *image)
1328 {
1329  assert(image != (Image *) NULL);
1330  assert(image->signature == MagickCoreSignature);
1331  if (IsEventLogging() != MagickFalse)
1332  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1333  DisassociateBlob(image);
1334 }
1335 ␌
1336 /*
1337 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1338 % %
1339 % %
1340 % %
1341 % G e t I m a g e I n f o %
1342 % %
1343 % %
1344 % %
1345 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1346 %
1347 % GetImageInfo() initializes image_info to default values.
1348 %
1349 % The format of the GetImageInfo method is:
1350 %
1351 % void GetImageInfo(ImageInfo *image_info)
1352 %
1353 % A description of each parameter follows:
1354 %
1355 % o image_info: the image info.
1356 %
1357 */
1358 MagickExport void GetImageInfo(ImageInfo *image_info)
1359 {
1360  char
1361  *synchronize;
1362 
1363  /*
1364  File and image dimension members.
1365  */
1366  assert(image_info != (ImageInfo *) NULL);
1367  if (IsEventLogging() != MagickFalse)
1368  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1369  (void) memset(image_info,0,sizeof(*image_info));
1370  image_info->adjoin=MagickTrue;
1371  image_info->interlace=NoInterlace;
1372  image_info->channel=AllChannels;
1373  image_info->quality=UndefinedCompressionQuality;
1374  image_info->antialias=MagickTrue;
1375  image_info->dither=MagickTrue;
1376  image_info->depth=0;
1377  synchronize=GetEnvironmentValue("MAGICK_SYNCHRONIZE");
1378  if (synchronize != (const char *) NULL)
1379  {
1380  image_info->synchronize=IsStringTrue(synchronize);
1381  synchronize=DestroyString(synchronize);
1382  }
1383  GetPixelInfoRGBA(BackgroundColorRGBA,&image_info->background_color);
1384  GetPixelInfoRGBA(BorderColorRGBA,&image_info->border_color);
1385  GetPixelInfoRGBA(MatteColorRGBA,&image_info->matte_color);
1386  GetPixelInfoRGBA(TransparentColorRGBA,&image_info->transparent_color);
1387  image_info->debug=(GetLogEventMask() & ImageEvent) != 0 ? MagickTrue :
1388  MagickFalse;
1389  image_info->signature=MagickCoreSignature;
1390 }
1391 ␌
1392 /*
1393 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1394 % %
1395 % %
1396 % %
1397 % G e t I m a g e I n f o F i l e %
1398 % %
1399 % %
1400 % %
1401 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1402 %
1403 % GetImageInfoFile() returns the image info file member.
1404 %
1405 % The format of the GetImageInfoFile method is:
1406 %
1407 % FILE *GetImageInfoFile(const ImageInfo *image_info)
1408 %
1409 % A description of each parameter follows:
1410 %
1411 % o image_info: the image info.
1412 %
1413 */
1414 MagickExport FILE *GetImageInfoFile(const ImageInfo *image_info)
1415 {
1416  return(image_info->file);
1417 }
1418 ␌
1419 /*
1420 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1421 % %
1422 % %
1423 % %
1424 % G e t I m a g e M a s k %
1425 % %
1426 % %
1427 % %
1428 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1429 %
1430 % GetImageMask() returns the mask associated with the image.
1431 %
1432 % The format of the GetImageMask method is:
1433 %
1434 % Image *GetImageMask(const Image *image,const PixelMask type,
1435 % ExceptionInfo *exception)
1436 %
1437 % A description of each parameter follows:
1438 %
1439 % o image: the image.
1440 %
1441 % o type: the mask type, ReadPixelMask or WritePixelMask.
1442 %
1443 */
1444 MagickExport Image *GetImageMask(const Image *image,const PixelMask type,
1445  ExceptionInfo *exception)
1446 {
1447  CacheView
1448  *mask_view,
1449  *image_view;
1450 
1451  Image
1452  *mask_image;
1453 
1454  MagickBooleanType
1455  status;
1456 
1457  ssize_t
1458  y;
1459 
1460  /*
1461  Get image mask.
1462  */
1463  assert(image != (Image *) NULL);
1464  assert(image->signature == MagickCoreSignature);
1465  if (IsEventLogging() != MagickFalse)
1466  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1467  switch (type)
1468  {
1469  case ReadPixelMask:
1470  {
1471  if ((image->channels & ReadMaskChannel) == 0)
1472  return((Image *) NULL);
1473  break;
1474  }
1475  case WritePixelMask:
1476  {
1477  if ((image->channels & WriteMaskChannel) == 0)
1478  return((Image *) NULL);
1479  break;
1480  }
1481  default:
1482  {
1483  if ((image->channels & CompositeMaskChannel) == 0)
1484  return((Image *) NULL);
1485  break;
1486  }
1487  }
1488  mask_image=AcquireImage((ImageInfo *) NULL,exception);
1489  status=SetImageExtent(mask_image,image->columns,image->rows,exception);
1490  if (status == MagickFalse)
1491  return(DestroyImage(mask_image));
1492  status=MagickTrue;
1493  mask_image->alpha_trait=UndefinedPixelTrait;
1494  (void) SetImageColorspace(mask_image,GRAYColorspace,exception);
1495  image_view=AcquireVirtualCacheView(image,exception);
1496  mask_view=AcquireAuthenticCacheView(mask_image,exception);
1497 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1498  #pragma omp parallel for schedule(static) shared(status) \
1499  magick_number_threads(image,image,image->rows,2)
1500 #endif
1501  for (y=0; y < (ssize_t) image->rows; y++)
1502  {
1503  const Quantum
1504  *magick_restrict p;
1505 
1506  Quantum
1507  *magick_restrict q;
1508 
1509  ssize_t
1510  x;
1511 
1512  if (status == MagickFalse)
1513  continue;
1514  p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1515  q=GetCacheViewAuthenticPixels(mask_view,0,y,mask_image->columns,1,
1516  exception);
1517  if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
1518  {
1519  status=MagickFalse;
1520  continue;
1521  }
1522  for (x=0; x < (ssize_t) image->columns; x++)
1523  {
1524  switch (type)
1525  {
1526  case ReadPixelMask:
1527  {
1528  SetPixelGray(mask_image,GetPixelReadMask(image,p),q);
1529  break;
1530  }
1531  case WritePixelMask:
1532  {
1533  SetPixelGray(mask_image,GetPixelWriteMask(image,p),q);
1534  break;
1535  }
1536  default:
1537  {
1538  SetPixelGray(mask_image,GetPixelCompositeMask(image,p),q);
1539  break;
1540  }
1541  }
1542  p+=(ptrdiff_t) GetPixelChannels(image);
1543  q+=(ptrdiff_t) GetPixelChannels(mask_image);
1544  }
1545  if (SyncCacheViewAuthenticPixels(mask_view,exception) == MagickFalse)
1546  status=MagickFalse;
1547  }
1548  mask_view=DestroyCacheView(mask_view);
1549  image_view=DestroyCacheView(image_view);
1550  if (status == MagickFalse)
1551  mask_image=DestroyImage(mask_image);
1552  return(mask_image);
1553 }
1554 ␌
1555 /*
1556 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1557 % %
1558 % %
1559 % %
1560 + G e t I m a g e R e f e r e n c e C o u n t %
1561 % %
1562 % %
1563 % %
1564 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1565 %
1566 % GetImageReferenceCount() returns the image reference count.
1567 %
1568 % The format of the GetReferenceCount method is:
1569 %
1570 % ssize_t GetImageReferenceCount(Image *image)
1571 %
1572 % A description of each parameter follows:
1573 %
1574 % o image: the image.
1575 %
1576 */
1577 MagickExport ssize_t GetImageReferenceCount(Image *image)
1578 {
1579  ssize_t
1580  reference_count;
1581 
1582  assert(image != (Image *) NULL);
1583  assert(image->signature == MagickCoreSignature);
1584  if (IsEventLogging() != MagickFalse)
1585  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1586  LockSemaphoreInfo(image->semaphore);
1587  reference_count=image->reference_count;
1588  UnlockSemaphoreInfo(image->semaphore);
1589  return(reference_count);
1590 }
1591 ␌
1592 /*
1593 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1594 % %
1595 % %
1596 % %
1597 % G e t I m a g e V i r t u a l P i x e l M e t h o d %
1598 % %
1599 % %
1600 % %
1601 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1602 %
1603 % GetImageVirtualPixelMethod() gets the "virtual pixels" method for the
1604 % image. A virtual pixel is any pixel access that is outside the boundaries
1605 % of the image cache.
1606 %
1607 % The format of the GetImageVirtualPixelMethod() method is:
1608 %
1609 % VirtualPixelMethod GetImageVirtualPixelMethod(const Image *image)
1610 %
1611 % A description of each parameter follows:
1612 %
1613 % o image: the image.
1614 %
1615 */
1616 MagickExport VirtualPixelMethod GetImageVirtualPixelMethod(const Image *image)
1617 {
1618  assert(image != (Image *) NULL);
1619  assert(image->signature == MagickCoreSignature);
1620  if (IsEventLogging() != MagickFalse)
1621  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1622  return(GetPixelCacheVirtualMethod(image));
1623 }
1624 ␌
1625 /*
1626 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1627 % %
1628 % %
1629 % %
1630 % I n t e r p r e t I m a g e F i l e n a m e %
1631 % %
1632 % %
1633 % %
1634 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1635 %
1636 % InterpretImageFilename() interprets embedded characters in an image filename.
1637 % The filename length is returned.
1638 %
1639 % The format of the InterpretImageFilename method is:
1640 %
1641 % size_t InterpretImageFilename(const ImageInfo *image_info,Image *image,
1642 % const char *format,int value,char *filename,ExceptionInfo *exception)
1643 %
1644 % A description of each parameter follows.
1645 %
1646 % o image_info: the image info.
1647 %
1648 % o image: the image.
1649 %
1650 % o format: A filename describing the format to use to write the numeric
1651 % argument. Only the first numeric format identifier is replaced.
1652 %
1653 % o value: Numeric value to substitute into format filename.
1654 %
1655 % o filename: return the formatted filename in this character buffer.
1656 %
1657 % o exception: return any errors or warnings in this structure.
1658 %
1659 */
1660 
1661 static inline MagickBooleanType IsValidFormatSpecifier(const char *start,
1662  const char *end)
1663 {
1664  char
1665  specifier = end[-1];
1666 
1667  size_t
1668  length = (size_t) (end-start);
1669 
1670  /*
1671  Is this a valid format specifier?
1672  */
1673  if ((specifier != 'd') && (specifier != 'x') && (specifier != 'o'))
1674  return(MagickFalse);
1675  if ((length == 1) && (*start == specifier))
1676  return(MagickTrue);
1677  if (length >= 2)
1678  {
1679  size_t
1680  i = 0;
1681 
1682  if (*start == '0')
1683  {
1684  if ((length >= 3) && (start[1] == '0'))
1685  return(MagickFalse);
1686  i=1;
1687  }
1688  for ( ; i < (length-1); i++)
1689  if (isdigit((int) ((unsigned char) start[i])) == 0)
1690  return(MagickFalse);
1691  return(MagickTrue);
1692  }
1693  return(MagickFalse);
1694 }
1695 
1696 MagickExport size_t InterpretImageFilename(const ImageInfo *image_info,
1697  Image *image,const char *format,int value,char *filename,
1698  ExceptionInfo *exception)
1699 {
1700  char
1701  *literal,
1702  *p = filename,
1703  pattern[MagickPathExtent];
1704 
1705  const char
1706  *cursor = format;
1707 
1708  assert(format != (const char *) NULL);
1709  assert(filename != (char *) NULL);
1710  literal=(char *) GetImageRegistry(StringRegistryType,"filename:literal",
1711  exception);
1712  if (IsStringTrue(literal) != MagickFalse)
1713  {
1714  if (literal != (char *) NULL)
1715  literal=DestroyString(literal);
1716  (void) CopyMagickString(filename,format,MagickPathExtent);
1717  return(strlen(filename));
1718  }
1719  if (literal != (char *) NULL)
1720  literal=DestroyString(literal);
1721  while ((*cursor != '\0') && ((p-filename) < ((ssize_t) MagickPathExtent-1)))
1722  {
1723  const char
1724  *specifier_start,
1725  *start;
1726 
1727  if (*cursor != '%')
1728  {
1729  *p++=(*cursor++);
1730  continue;
1731  }
1732  start=cursor++; /* Skip '%' */
1733  if (*cursor == '%')
1734  {
1735  *p++='%';
1736  cursor++;
1737  continue;
1738  }
1739  specifier_start=cursor;
1740  while (isdigit((int) ((unsigned char) *cursor)) != 0)
1741  cursor++;
1742  if ((*cursor == 'd') || (*cursor == 'o') || (*cursor == 'x'))
1743  {
1744  const char
1745  *specifier_end = cursor+1;
1746 
1747  if (IsValidFormatSpecifier(specifier_start,specifier_end) != MagickFalse)
1748  {
1749  char
1750  format_specifier[MagickPathExtent];
1751 
1752  size_t
1753  length = (size_t) (cursor-specifier_start),
1754  pattern_length;
1755 
1756  ssize_t
1757  count;
1758 
1759  (void) snprintf(format_specifier,sizeof(format_specifier),
1760  "%%%.*s%c",(int) length,specifier_start,*cursor);
1761  count=FormatLocaleString(pattern,sizeof(pattern),format_specifier,
1762  value);
1763  pattern_length=strlen(pattern);
1764  if ((count <= 0) || ((size_t) count != pattern_length))
1765  return(0);
1766  if ((p-filename+pattern_length) >= MagickPathExtent)
1767  return(0);
1768  (void) CopyMagickString(p,pattern,(size_t) (MagickPathExtent-
1769  (p-filename)));
1770  p+=pattern_length;
1771  cursor++;
1772  continue;
1773  }
1774  else
1775  {
1776  /*
1777  Invalid specifier — treat as literal.
1778  */
1779  cursor=start;
1780  *p++=(*cursor++);
1781  continue;
1782  }
1783  }
1784  if (*cursor == '[')
1785  {
1786  const char
1787  *end = strchr(cursor,']'),
1788  *option = (const char *) NULL;
1789 
1790  size_t
1791  extent,
1792  option_length;
1793 
1794  if (end == (const char *) NULL)
1795  continue;
1796  extent=(size_t) (end-cursor-1);
1797  if (extent >= sizeof(pattern))
1798  continue;
1799  (void) CopyMagickString(pattern,cursor+1,extent+1);
1800  pattern[extent]='\0';
1801  if (image != NULL)
1802  {
1803  option=GetImageProperty(image,pattern,exception);
1804  if (option == (const char *) NULL)
1805  option=GetImageArtifact(image,pattern);
1806  }
1807  if ((option == (const char *) NULL) &&
1808  (image_info != (ImageInfo *) NULL))
1809  option=GetImageOption(image_info,pattern);
1810  if (option == (const char *) NULL)
1811  continue;
1812  option_length=strlen(option);
1813  if ((p-filename+option_length) >= MagickPathExtent)
1814  return(0);
1815  (void) CopyMagickString(p,option,(size_t) (MagickPathExtent-
1816  (p-filename)));
1817  p+=option_length;
1818  cursor=end+1;
1819  continue;
1820  }
1821  /*
1822  Invalid or unsupported specifier — treat as literal.
1823  */
1824  cursor=start;
1825  if ((p-filename+1) >= MagickPathExtent)
1826  return(0);
1827  *p++=(*cursor++);
1828  }
1829  *p='\0';
1830  return(strlen(filename));
1831 }
1832 ␌
1833 /*
1834 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1835 % %
1836 % %
1837 % %
1838 % I s H i g h D y n a m i c R a n g e I m a g e %
1839 % %
1840 % %
1841 % %
1842 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1843 %
1844 % IsHighDynamicRangeImage() returns MagickTrue if any pixel component is
1845 % non-integer or exceeds the bounds of the quantum depth (e.g. for Q16
1846 % 0..65535.
1847 %
1848 % The format of the IsHighDynamicRangeImage method is:
1849 %
1850 % MagickBooleanType IsHighDynamicRangeImage(const Image *image,
1851 % ExceptionInfo *exception)
1852 %
1853 % A description of each parameter follows:
1854 %
1855 % o image: the image.
1856 %
1857 % o exception: return any errors or warnings in this structure.
1858 %
1859 */
1860 MagickExport MagickBooleanType IsHighDynamicRangeImage(const Image *image,
1861  ExceptionInfo *exception)
1862 {
1863 #if !defined(MAGICKCORE_HDRI_SUPPORT)
1864  (void) image;
1865  (void) exception;
1866  return(MagickFalse);
1867 #else
1868  CacheView
1869  *image_view;
1870 
1871  MagickBooleanType
1872  hdri = MagickFalse;
1873 
1874  ssize_t
1875  y;
1876 
1877  assert(image != (Image *) NULL);
1878  assert(image->signature == MagickCoreSignature);
1879  if (IsEventLogging() != MagickFalse)
1880  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1881  image_view=AcquireVirtualCacheView(image,exception);
1882 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1883  #pragma omp parallel for schedule(static) shared(hdri) \
1884  magick_number_threads(image,image,image->rows,2)
1885 #endif
1886  for (y=0; y < (ssize_t) image->rows; y++)
1887  {
1888  const Quantum
1889  *p;
1890 
1891  ssize_t
1892  x;
1893 
1894  if (hdri != MagickFalse)
1895  continue;
1896  p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1897  if (p == (const Quantum *) NULL)
1898  continue;
1899  for (x=0; x < (ssize_t) image->columns; x++)
1900  {
1901  ssize_t
1902  i;
1903 
1904  for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1905  {
1906  double
1907  pixel;
1908 
1909  PixelTrait
1910  traits;
1911 
1912  traits=GetPixelChannelTraits(image,(PixelChannel) i);
1913  if (traits == UndefinedPixelTrait)
1914  continue;
1915  pixel=(double) p[i];
1916  if ((pixel < 0.0) || (pixel > (double) QuantumRange) ||
1917  (pixel != (double) ((QuantumAny) pixel)))
1918  {
1919  hdri=MagickTrue;
1920  break;
1921  }
1922  }
1923  if (hdri != MagickFalse)
1924  break;
1925  p+=(ptrdiff_t) GetPixelChannels(image);
1926  }
1927  }
1928  image_view=DestroyCacheView(image_view);
1929  return(hdri);
1930 #endif
1931 }
1932 ␌
1933 /*
1934 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1935 % %
1936 % %
1937 % %
1938 % I s I m a g e O b j e c t %
1939 % %
1940 % %
1941 % %
1942 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1943 %
1944 % IsImageObject() returns MagickTrue if the image sequence contains a valid
1945 % set of image objects.
1946 %
1947 % The format of the IsImageObject method is:
1948 %
1949 % MagickBooleanType IsImageObject(const Image *image)
1950 %
1951 % A description of each parameter follows:
1952 %
1953 % o image: the image.
1954 %
1955 */
1956 MagickExport MagickBooleanType IsImageObject(const Image *image)
1957 {
1958  const Image
1959  *p;
1960 
1961  assert(image != (Image *) NULL);
1962  if (IsEventLogging() != MagickFalse)
1963  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1964  for (p=image; p != (Image *) NULL; p=GetNextImageInList(p))
1965  if (p->signature != MagickCoreSignature)
1966  return(MagickFalse);
1967  return(MagickTrue);
1968 }
1969 ␌
1970 /*
1971 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1972 % %
1973 % %
1974 % %
1975 % I s T a i n t I m a g e %
1976 % %
1977 % %
1978 % %
1979 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1980 %
1981 % IsTaintImage() returns MagickTrue any pixel in the image has been altered
1982 % since it was first constituted.
1983 %
1984 % The format of the IsTaintImage method is:
1985 %
1986 % MagickBooleanType IsTaintImage(const Image *image)
1987 %
1988 % A description of each parameter follows:
1989 %
1990 % o image: the image.
1991 %
1992 */
1993 MagickExport MagickBooleanType IsTaintImage(const Image *image)
1994 {
1995  char
1996  magick[MagickPathExtent],
1997  filename[MagickPathExtent];
1998 
1999  const Image
2000  *p;
2001 
2002  assert(image != (Image *) NULL);
2003  assert(image->signature == MagickCoreSignature);
2004  if (IsEventLogging() != MagickFalse)
2005  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2006  (void) CopyMagickString(magick,image->magick,MagickPathExtent);
2007  (void) CopyMagickString(filename,image->filename,MagickPathExtent);
2008  for (p=image; p != (Image *) NULL; p=GetNextImageInList(p))
2009  {
2010  if (p->taint != MagickFalse)
2011  return(MagickTrue);
2012  if (LocaleCompare(p->magick,magick) != 0)
2013  return(MagickTrue);
2014  if (LocaleCompare(p->filename,filename) != 0)
2015  return(MagickTrue);
2016  }
2017  return(MagickFalse);
2018 }
2019 ␌
2020 /*
2021 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2022 % %
2023 % %
2024 % %
2025 % M o d i f y I m a g e %
2026 % %
2027 % %
2028 % %
2029 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2030 %
2031 % ModifyImage() ensures that there is only a single reference to the image
2032 % to be modified, updating the provided image pointer to point to a clone of
2033 % the original image if necessary.
2034 %
2035 % The format of the ModifyImage method is:
2036 %
2037 % MagickBooleanType ModifyImage(Image *image,ExceptionInfo *exception)
2038 %
2039 % A description of each parameter follows:
2040 %
2041 % o image: the image.
2042 %
2043 % o exception: return any errors or warnings in this structure.
2044 %
2045 */
2046 MagickExport MagickBooleanType ModifyImage(Image **image,
2047  ExceptionInfo *exception)
2048 {
2049  Image
2050  *clone_image;
2051 
2052  assert(image != (Image **) NULL);
2053  assert(*image != (Image *) NULL);
2054  assert((*image)->signature == MagickCoreSignature);
2055  if (IsEventLogging() != MagickFalse)
2056  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",(*image)->filename);
2057  if (GetImageReferenceCount(*image) <= 1)
2058  return(MagickTrue);
2059  clone_image=CloneImage(*image,0,0,MagickTrue,exception);
2060  LockSemaphoreInfo((*image)->semaphore);
2061  (*image)->reference_count--;
2062  UnlockSemaphoreInfo((*image)->semaphore);
2063  *image=clone_image;
2064  return(MagickTrue);
2065 }
2066 ␌
2067 /*
2068 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2069 % %
2070 % %
2071 % %
2072 % N e w M a g i c k I m a g e %
2073 % %
2074 % %
2075 % %
2076 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2077 %
2078 % NewMagickImage() creates a blank image canvas of the specified size and
2079 % background color.
2080 %
2081 % The format of the NewMagickImage method is:
2082 %
2083 % Image *NewMagickImage(const ImageInfo *image_info,const size_t width,
2084 % const size_t height,const PixelInfo *background,
2085 % ExceptionInfo *exception)
2086 %
2087 % A description of each parameter follows:
2088 %
2089 % o image: the image.
2090 %
2091 % o width: the image width.
2092 %
2093 % o height: the image height.
2094 %
2095 % o background: the image color.
2096 %
2097 % o exception: return any errors or warnings in this structure.
2098 %
2099 */
2100 MagickExport Image *NewMagickImage(const ImageInfo *image_info,
2101  const size_t width,const size_t height,const PixelInfo *background,
2102  ExceptionInfo *exception)
2103 {
2104  CacheView
2105  *image_view;
2106 
2107  Image
2108  *image;
2109 
2110  MagickBooleanType
2111  status;
2112 
2113  ssize_t
2114  y;
2115 
2116  assert(image_info != (const ImageInfo *) NULL);
2117  assert(image_info->signature == MagickCoreSignature);
2118  assert(background != (const PixelInfo *) NULL);
2119  if (IsEventLogging() != MagickFalse)
2120  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2121  image=AcquireImage(image_info,exception);
2122  image->columns=width;
2123  image->rows=height;
2124  image->colorspace=background->colorspace;
2125  image->alpha_trait=background->alpha_trait;
2126  image->fuzz=background->fuzz;
2127  image->depth=background->depth;
2128  status=MagickTrue;
2129  image_view=AcquireAuthenticCacheView(image,exception);
2130 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2131  #pragma omp parallel for schedule(static) shared(status) \
2132  magick_number_threads(image,image,image->rows,2)
2133 #endif
2134  for (y=0; y < (ssize_t) image->rows; y++)
2135  {
2136  Quantum
2137  *magick_restrict q;
2138 
2139  ssize_t
2140  x;
2141 
2142  if (status == MagickFalse)
2143  continue;
2144  q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2145  if (q == (Quantum *) NULL)
2146  {
2147  status=MagickFalse;
2148  continue;
2149  }
2150  for (x=0; x < (ssize_t) image->columns; x++)
2151  {
2152  SetPixelViaPixelInfo(image,background,q);
2153  q+=(ptrdiff_t) GetPixelChannels(image);
2154  }
2155  if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2156  status=MagickFalse;
2157  }
2158  image_view=DestroyCacheView(image_view);
2159  if (status == MagickFalse)
2160  image=DestroyImage(image);
2161  return(image);
2162 }
2163 ␌
2164 /*
2165 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2166 % %
2167 % %
2168 % %
2169 % R e f e r e n c e I m a g e %
2170 % %
2171 % %
2172 % %
2173 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2174 %
2175 % ReferenceImage() increments the reference count associated with an image
2176 % returning a pointer to the image.
2177 %
2178 % The format of the ReferenceImage method is:
2179 %
2180 % Image *ReferenceImage(Image *image)
2181 %
2182 % A description of each parameter follows:
2183 %
2184 % o image: the image.
2185 %
2186 */
2187 MagickExport Image *ReferenceImage(Image *image)
2188 {
2189  assert(image != (Image *) NULL);
2190  assert(image->signature == MagickCoreSignature);
2191  if (IsEventLogging() != MagickFalse)
2192  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2193  LockSemaphoreInfo(image->semaphore);
2194  image->reference_count++;
2195  UnlockSemaphoreInfo(image->semaphore);
2196  return(image);
2197 }
2198 ␌
2199 /*
2200 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2201 % %
2202 % %
2203 % %
2204 % R e s e t I m a g e P a g e %
2205 % %
2206 % %
2207 % %
2208 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2209 %
2210 % ResetImagePage() resets the image page canvas and position.
2211 %
2212 % The format of the ResetImagePage method is:
2213 %
2214 % MagickBooleanType ResetImagePage(Image *image,const char *page)
2215 %
2216 % A description of each parameter follows:
2217 %
2218 % o image: the image.
2219 %
2220 % o page: the relative page specification.
2221 %
2222 */
2223 MagickExport MagickBooleanType ResetImagePage(Image *image,const char *page)
2224 {
2225  MagickStatusType
2226  flags;
2227 
2229  geometry;
2230 
2231  assert(image != (Image *) NULL);
2232  assert(image->signature == MagickCoreSignature);
2233  if (IsEventLogging() != MagickFalse)
2234  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2235  flags=ParseAbsoluteGeometry(page,&geometry);
2236  if ((flags & WidthValue) != 0)
2237  {
2238  if ((flags & HeightValue) == 0)
2239  geometry.height=geometry.width;
2240  image->page.width=geometry.width;
2241  image->page.height=geometry.height;
2242  }
2243  if ((flags & AspectValue) != 0)
2244  {
2245  if ((flags & XValue) != 0)
2246  image->page.x+=geometry.x;
2247  if ((flags & YValue) != 0)
2248  image->page.y+=geometry.y;
2249  }
2250  else
2251  {
2252  if ((flags & XValue) != 0)
2253  {
2254  image->page.x=geometry.x;
2255  if ((image->page.width == 0) && (geometry.x > 0))
2256  image->page.width=(size_t) ((ssize_t) image->columns+geometry.x);
2257  }
2258  if ((flags & YValue) != 0)
2259  {
2260  image->page.y=geometry.y;
2261  if ((image->page.height == 0) && (geometry.y > 0))
2262  image->page.height=(size_t) ((ssize_t) image->rows+geometry.y);
2263  }
2264  }
2265  return(MagickTrue);
2266 }
2267 ␌
2268 /*
2269 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2270 % %
2271 % %
2272 % %
2273 % R e s e t I m a g e P i x e l s %
2274 % %
2275 % %
2276 % %
2277 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2278 %
2279 % ResetImagePixels() reset the image pixels, that is, all the pixel components
2280 % are zeroed.
2281 %
2282 % The format of the SetImage method is:
2283 %
2284 % MagickBooleanType ResetImagePixels(Image *image,
2285 % ExceptionInfo *exception)
2286 %
2287 % A description of each parameter follows:
2288 %
2289 % o image: the image.
2290 %
2291 % o exception: return any errors or warnings in this structure.
2292 %
2293 */
2294 MagickExport MagickBooleanType ResetImagePixels(Image *image,
2295  ExceptionInfo *exception)
2296 {
2297  CacheView
2298  *image_view;
2299 
2300  MagickBooleanType
2301  status;
2302 
2303  size_t
2304  length;
2305 
2306  ssize_t
2307  y;
2308 
2309  void
2310  *pixels;
2311 
2312  assert(image != (Image *) NULL);
2313  assert(image->signature == MagickCoreSignature);
2314  if (IsEventLogging() != MagickFalse)
2315  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2316  pixels=AcquirePixelCachePixels(image,&length,exception);
2317  if (pixels != (void *) NULL)
2318  {
2319  /*
2320  Reset in-core image pixels.
2321  */
2322  (void) memset(pixels,0,length);
2323  return(MagickTrue);
2324  }
2325  /*
2326  Reset image pixels.
2327  */
2328  status=MagickTrue;
2329  image_view=AcquireAuthenticCacheView(image,exception);
2330 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2331  #pragma omp parallel for schedule(static) shared(status) \
2332  magick_number_threads(image,image,image->rows,2)
2333 #endif
2334  for (y=0; y < (ssize_t) image->rows; y++)
2335  {
2336  Quantum
2337  *magick_restrict q;
2338 
2339  ssize_t
2340  x;
2341 
2342  if (status == MagickFalse)
2343  continue;
2344  q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2345  if (q == (Quantum *) NULL)
2346  {
2347  status=MagickFalse;
2348  continue;
2349  }
2350  for (x=0; x < (ssize_t) image->columns; x++)
2351  {
2352  (void) memset(q,0,GetPixelChannels(image)*sizeof(Quantum));
2353  q+=(ptrdiff_t) GetPixelChannels(image);
2354  }
2355  if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2356  status=MagickFalse;
2357  }
2358  image_view=DestroyCacheView(image_view);
2359  return(status);
2360 }
2361 ␌
2362 /*
2363 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2364 % %
2365 % %
2366 % %
2367 % S e t I m a g e A l p h a %
2368 % %
2369 % %
2370 % %
2371 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2372 %
2373 % SetImageAlpha() sets the alpha levels of the image.
2374 %
2375 % The format of the SetImageAlpha method is:
2376 %
2377 % MagickBooleanType SetImageAlpha(Image *image,const Quantum alpha,
2378 % ExceptionInfo *exception)
2379 %
2380 % A description of each parameter follows:
2381 %
2382 % o image: the image.
2383 %
2384 % o alpha: the level of transparency: 0 is fully transparent and QuantumRange
2385 % is fully opaque.
2386 %
2387 % o exception: return any errors or warnings in this structure.
2388 %
2389 */
2390 MagickExport MagickBooleanType SetImageAlpha(Image *image,const Quantum alpha,
2391  ExceptionInfo *exception)
2392 {
2393  CacheView
2394  *image_view;
2395 
2396  MagickBooleanType
2397  status;
2398 
2399  PixelTrait
2400  original_mask;
2401 
2402  ssize_t
2403  y;
2404 
2405  assert(image != (Image *) NULL);
2406  assert(image->signature == MagickCoreSignature);
2407  if (IsEventLogging() != MagickFalse)
2408  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2409  image->alpha_trait=BlendPixelTrait;
2410  /* Disable mask to make sure that all pixels are changed */
2411  original_mask=image->mask_trait;
2412  image->mask_trait=UndefinedPixelTrait;
2413  status=MagickTrue;
2414  image_view=AcquireAuthenticCacheView(image,exception);
2415 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2416  #pragma omp parallel for schedule(static) shared(status) \
2417  magick_number_threads(image,image,image->rows,2)
2418 #endif
2419  for (y=0; y < (ssize_t) image->rows; y++)
2420  {
2421  Quantum
2422  *magick_restrict q;
2423 
2424  ssize_t
2425  x;
2426 
2427  if (status == MagickFalse)
2428  continue;
2429  q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2430  if (q == (Quantum *) NULL)
2431  {
2432  status=MagickFalse;
2433  continue;
2434  }
2435  for (x=0; x < (ssize_t) image->columns; x++)
2436  {
2437  if (GetPixelWriteMask(image,q) > (QuantumRange/2))
2438  SetPixelAlpha(image,alpha,q);
2439  q+=(ptrdiff_t) GetPixelChannels(image);
2440  }
2441  if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2442  status=MagickFalse;
2443  }
2444  image_view=DestroyCacheView(image_view);
2445  image->mask_trait=original_mask;
2446  return(status);
2447 }
2448 ␌
2449 /*
2450 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2451 % %
2452 % %
2453 % %
2454 % S e t I m a g e B a c k g r o u n d C o l o r %
2455 % %
2456 % %
2457 % %
2458 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2459 %
2460 % SetImageBackgroundColor() initializes the image pixels to the image
2461 % background color. The background color is defined by the background_color
2462 % member of the image structure.
2463 %
2464 % The format of the SetImage method is:
2465 %
2466 % MagickBooleanType SetImageBackgroundColor(Image *image,
2467 % ExceptionInfo *exception)
2468 %
2469 % A description of each parameter follows:
2470 %
2471 % o image: the image.
2472 %
2473 % o exception: return any errors or warnings in this structure.
2474 %
2475 */
2476 MagickExport MagickBooleanType SetImageBackgroundColor(Image *image,
2477  ExceptionInfo *exception)
2478 {
2479  CacheView
2480  *image_view;
2481 
2482  MagickBooleanType
2483  status;
2484 
2485  PixelInfo
2486  background;
2487 
2488  ssize_t
2489  y;
2490 
2491  assert(image != (Image *) NULL);
2492  assert(image->signature == MagickCoreSignature);
2493  if (IsEventLogging() != MagickFalse)
2494  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2495  if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
2496  return(MagickFalse);
2497  if ((image->background_color.alpha_trait != UndefinedPixelTrait) &&
2498  ((image->alpha_trait & BlendPixelTrait) == 0))
2499  (void) SetImageAlphaChannel(image,ActivateAlphaChannel,exception);
2500  ConformPixelInfo(image,&image->background_color,&background,exception);
2501  /*
2502  Set image background color.
2503  */
2504  status=MagickTrue;
2505  image_view=AcquireAuthenticCacheView(image,exception);
2506 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2507  #pragma omp parallel for schedule(static) shared(status) \
2508  magick_number_threads(image,image,image->rows,2)
2509 #endif
2510  for (y=0; y < (ssize_t) image->rows; y++)
2511  {
2512  Quantum
2513  *magick_restrict q;
2514 
2515  ssize_t
2516  x;
2517 
2518  if (status == MagickFalse)
2519  continue;
2520  q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2521  if (q == (Quantum *) NULL)
2522  {
2523  status=MagickFalse;
2524  continue;
2525  }
2526  for (x=0; x < (ssize_t) image->columns; x++)
2527  {
2528  SetPixelViaPixelInfo(image,&background,q);
2529  q+=(ptrdiff_t) GetPixelChannels(image);
2530  }
2531  if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2532  status=MagickFalse;
2533  }
2534  image_view=DestroyCacheView(image_view);
2535  return(status);
2536 }
2537 ␌
2538 /*
2539 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2540 % %
2541 % %
2542 % %
2543 % S e t I m a g e C h a n n e l M a s k %
2544 % %
2545 % %
2546 % %
2547 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2548 %
2549 % SetImageChannelMask() sets the image channel mask from the specified channel
2550 % mask.
2551 %
2552 % The format of the SetImageChannelMask method is:
2553 %
2554 % ChannelType SetImageChannelMask(Image *image,
2555 % const ChannelType channel_mask)
2556 %
2557 % A description of each parameter follows:
2558 %
2559 % o image: the image.
2560 %
2561 % o channel_mask: the channel mask.
2562 %
2563 */
2564 MagickExport ChannelType SetImageChannelMask(Image *image,
2565  const ChannelType channel_mask)
2566 {
2567  return(SetPixelChannelMask(image,channel_mask));
2568 }
2569 ␌
2570 /*
2571 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2572 % %
2573 % %
2574 % %
2575 % S e t I m a g e C o l o r %
2576 % %
2577 % %
2578 % %
2579 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2580 %
2581 % SetImageColor() set the entire image canvas to the specified color.
2582 %
2583 % The format of the SetImageColor method is:
2584 %
2585 % MagickBooleanType SetImageColor(Image *image,const PixelInfo *color,
2586 % ExceptionInfo *exception)
2587 %
2588 % A description of each parameter follows:
2589 %
2590 % o image: the image.
2591 %
2592 % o background: the image color.
2593 %
2594 % o exception: return any errors or warnings in this structure.
2595 %
2596 */
2597 MagickExport MagickBooleanType SetImageColor(Image *image,
2598  const PixelInfo *color,ExceptionInfo *exception)
2599 {
2600  CacheView
2601  *image_view;
2602 
2603  MagickBooleanType
2604  status;
2605 
2606  ssize_t
2607  y;
2608 
2609  assert(image != (Image *) NULL);
2610  assert(image->signature == MagickCoreSignature);
2611  assert(color != (const PixelInfo *) NULL);
2612  if (IsEventLogging() != MagickFalse)
2613  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2614  image->colorspace=color->colorspace;
2615  image->alpha_trait=color->alpha_trait;
2616  image->fuzz=color->fuzz;
2617  image->depth=color->depth;
2618  status=MagickTrue;
2619  image_view=AcquireAuthenticCacheView(image,exception);
2620 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2621  #pragma omp parallel for schedule(static) shared(status) \
2622  magick_number_threads(image,image,image->rows,2)
2623 #endif
2624  for (y=0; y < (ssize_t) image->rows; y++)
2625  {
2626  Quantum
2627  *magick_restrict q;
2628 
2629  ssize_t
2630  x;
2631 
2632  if (status == MagickFalse)
2633  continue;
2634  q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2635  if (q == (Quantum *) NULL)
2636  {
2637  status=MagickFalse;
2638  continue;
2639  }
2640  for (x=0; x < (ssize_t) image->columns; x++)
2641  {
2642  SetPixelViaPixelInfo(image,color,q);
2643  q+=(ptrdiff_t) GetPixelChannels(image);
2644  }
2645  if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2646  status=MagickFalse;
2647  }
2648  image_view=DestroyCacheView(image_view);
2649  return(status);
2650 }
2651 ␌
2652 /*
2653 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2654 % %
2655 % %
2656 % %
2657 % S e t I m a g e S t o r a g e C l a s s %
2658 % %
2659 % %
2660 % %
2661 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2662 %
2663 % SetImageStorageClass() sets the image class: DirectClass for true color
2664 % images or PseudoClass for colormapped images.
2665 %
2666 % The format of the SetImageStorageClass method is:
2667 %
2668 % MagickBooleanType SetImageStorageClass(Image *image,
2669 % const ClassType storage_class,ExceptionInfo *exception)
2670 %
2671 % A description of each parameter follows:
2672 %
2673 % o image: the image.
2674 %
2675 % o storage_class: The image class.
2676 %
2677 % o exception: return any errors or warnings in this structure.
2678 %
2679 */
2680 MagickExport MagickBooleanType SetImageStorageClass(Image *image,
2681  const ClassType storage_class,ExceptionInfo *exception)
2682 {
2683  assert(image != (Image *) NULL);
2684  assert(image->signature == MagickCoreSignature);
2685  assert(exception != (ExceptionInfo *) NULL);
2686  assert(exception->signature == MagickCoreSignature);
2687  if (IsEventLogging() != MagickFalse)
2688  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2689  image->storage_class=storage_class;
2690  return(SyncImagePixelCache(image,exception));
2691 }
2692 ␌
2693 /*
2694 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2695 % %
2696 % %
2697 % %
2698 % S e t I m a g e E x t e n t %
2699 % %
2700 % %
2701 % %
2702 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2703 %
2704 % SetImageExtent() sets the image size (i.e. columns & rows).
2705 %
2706 % The format of the SetImageExtent method is:
2707 %
2708 % MagickBooleanType SetImageExtent(Image *image,const size_t columns,
2709 % const size_t rows,ExceptionInfo *exception)
2710 %
2711 % A description of each parameter follows:
2712 %
2713 % o image: the image.
2714 %
2715 % o columns: The image width in pixels.
2716 %
2717 % o rows: The image height in pixels.
2718 %
2719 % o exception: return any errors or warnings in this structure.
2720 %
2721 */
2722 MagickExport MagickBooleanType SetImageExtent(Image *image,const size_t columns,
2723  const size_t rows,ExceptionInfo *exception)
2724 {
2725  if ((columns == 0) || (rows == 0))
2726  ThrowBinaryException(ImageError,"NegativeOrZeroImageSize",image->filename);
2727  if ((columns > (size_t) MAGICK_SSIZE_MAX) ||
2728  (rows > (size_t) MAGICK_SSIZE_MAX))
2729  ThrowBinaryException(ImageError,"ImageSizeLimitExceeded",image->filename);
2730  image->columns=columns;
2731  image->rows=rows;
2732  if (image->depth == 0)
2733  {
2734  image->depth=8;
2735  (void) ThrowMagickException(exception,GetMagickModule(),ImageError,
2736  "ImageDepthNotSupported","`%s'",image->filename);
2737  }
2738  if (image->depth > (8*sizeof(MagickSizeType)))
2739  {
2740  image->depth=8*sizeof(MagickSizeType);
2741  (void) ThrowMagickException(exception,GetMagickModule(),ImageError,
2742  "ImageDepthNotSupported","`%s'",image->filename);
2743  }
2744  return(SyncImagePixelCache(image,exception));
2745 }
2746 ␌
2747 /*
2748 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2749 % %
2750 % %
2751 % %
2752 + S e t I m a g e I n f o %
2753 % %
2754 % %
2755 % %
2756 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2757 %
2758 % SetImageInfo() initializes the 'magick' field of the ImageInfo structure.
2759 % It is set to a type of image format based on the prefix or suffix of the
2760 % filename. For example, 'ps:image' returns PS indicating a Postscript image.
2761 % JPEG is returned for this filename: 'image.jpg'. The filename prefix has
2762 % precedence over the suffix. Use an optional index enclosed in brackets
2763 % after a file name to specify a desired scene of a multi-resolution image
2764 % format like Photo CD (e.g. img0001.pcd[4]). A True (non-zero) return value
2765 % indicates success.
2766 %
2767 % The format of the SetImageInfo method is:
2768 %
2769 % MagickBooleanType SetImageInfo(ImageInfo *image_info,
2770 % const unsigned int frames,ExceptionInfo *exception)
2771 %
2772 % A description of each parameter follows:
2773 %
2774 % o image_info: the image info.
2775 %
2776 % o frames: the number of images you intend to write.
2777 %
2778 % o exception: return any errors or warnings in this structure.
2779 %
2780 */
2781 
2782 static const MagickInfo *SetImageInfoFromExtension(ImageInfo *image_info,
2783  const char *component,char *magic,ExceptionInfo *exception)
2784 {
2785  const MagickInfo
2786  *magick_info;
2787 
2788  MagickFormatType
2789  format_type;
2790 
2791  ssize_t
2792  i;
2793 
2794  static const char
2795  *format_type_formats[] =
2796  {
2797  "AUTOTRACE",
2798  "BROWSE",
2799  "DCRAW",
2800  "EDIT",
2801  "LAUNCH",
2802  "MPEG:DECODE",
2803  "MPEG:ENCODE",
2804  "PRINT",
2805  "PS:ALPHA",
2806  "PS:CMYK",
2807  "PS:COLOR",
2808  "PS:GRAY",
2809  "PS:MONO",
2810  "SCAN",
2811  "SHOW",
2812  "WIN",
2813  (char *) NULL
2814  };
2815 
2816  /*
2817  User specified image format.
2818  */
2819  (void) CopyMagickString(magic,component,MagickPathExtent);
2820  LocaleUpper(magic);
2821  /*
2822  Look for explicit image formats.
2823  */
2824  format_type=UndefinedFormatType;
2825  magick_info=GetMagickInfo(magic,exception);
2826  if ((magick_info != (const MagickInfo *) NULL) &&
2827  (magick_info->format_type != UndefinedFormatType))
2828  format_type=magick_info->format_type;
2829  i=0;
2830  while ((format_type == UndefinedFormatType) &&
2831  (format_type_formats[i] != (char *) NULL))
2832  {
2833  if ((*magic == *format_type_formats[i]) &&
2834  (LocaleCompare(magic,format_type_formats[i]) == 0))
2835  format_type=ExplicitFormatType;
2836  i++;
2837  }
2838  if (format_type == UndefinedFormatType)
2839  (void) CopyMagickString(image_info->magick,magic,MagickPathExtent);
2840  else
2841  if (format_type == ExplicitFormatType)
2842  {
2843  image_info->affirm=MagickTrue;
2844  (void) CopyMagickString(image_info->magick,magic,MagickPathExtent);
2845  }
2846  if (LocaleCompare(magic,"RGB") == 0)
2847  image_info->affirm=MagickFalse; /* maybe SGI disguised as RGB */
2848  return(magick_info);
2849 }
2850 
2851 MagickExport MagickBooleanType SetImageInfo(ImageInfo *image_info,
2852  const unsigned int frames,ExceptionInfo *exception)
2853 {
2854  char
2855  component[MagickPathExtent],
2856  magic[MagickPathExtent],
2857  path[MagickPathExtent],
2858  *q;
2859 
2860  const char
2861  *p;
2862 
2863  const MagicInfo
2864  *magic_info;
2865 
2866  const MagickInfo
2867  *magick_info;
2868 
2870  *sans_exception;
2871 
2872  Image
2873  *image;
2874 
2875  MagickBooleanType
2876  status;
2877 
2878  ssize_t
2879  count;
2880 
2881  /*
2882  Look for 'image.format' in filename.
2883  */
2884  assert(image_info != (ImageInfo *) NULL);
2885  assert(image_info->signature == MagickCoreSignature);
2886  if (IsEventLogging() != MagickFalse)
2887  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2888  image_info->filename);
2889  *component='\0';
2890  GetPathComponent(image_info->filename,SubimagePath,component);
2891  if (*component == '\0')
2892  {
2893  const char *image_frames = GetImageOption(image_info,"image:frames");
2894  if (image_frames != (const char *) NULL)
2895  (void) CopyMagickString(component,image_frames,MagickPathExtent);
2896  }
2897  if (*component != '\0')
2898  {
2899  /*
2900  Look for scene specification (e.g. img0001.pcd[4]).
2901  */
2902  if (IsSceneGeometry(component,MagickFalse) == MagickFalse)
2903  {
2904  if (IsGeometry(component) != MagickFalse)
2905  (void) CloneString(&image_info->extract,component);
2906  }
2907  else
2908  {
2909  size_t
2910  first,
2911  last;
2912 
2913  (void) CloneString(&image_info->scenes,component);
2914  image_info->scene=StringToUnsignedLong(image_info->scenes);
2915  image_info->number_scenes=image_info->scene;
2916  p=image_info->scenes;
2917  for (q=(char *) image_info->scenes; *q != '\0'; p++)
2918  {
2919  while ((isspace((int) ((unsigned char) *p)) != 0) || (*p == ','))
2920  p++;
2921  first=(size_t) strtol(p,&q,10);
2922  last=first;
2923  while (isspace((int) ((unsigned char) *q)) != 0)
2924  q++;
2925  if (*q == '-')
2926  last=(size_t) strtol(q+1,&q,10);
2927  if (first > last)
2928  Swap(first,last);
2929  if (first < image_info->scene)
2930  image_info->scene=first;
2931  if (last > image_info->number_scenes)
2932  image_info->number_scenes=last;
2933  p=q;
2934  }
2935  image_info->number_scenes-=image_info->scene-1;
2936  }
2937  }
2938  *component='\0';
2939  if (*image_info->magick == '\0')
2940  GetPathComponent(image_info->filename,ExtensionPath,component);
2941  if (*component != '\0')
2942  {
2943  /*
2944  Base path sans any compression extension.
2945  */
2946  GetPathComponent(image_info->filename,BasePathSansCompressExtension,path);
2947  GetPathComponent(path,ExtensionPath,component);
2948  }
2949  image_info->affirm=MagickFalse;
2950  sans_exception=AcquireExceptionInfo();
2951  if ((*component != '\0') && (IsGlob(component) == MagickFalse))
2952  magick_info=SetImageInfoFromExtension(image_info,component,magic,
2953  sans_exception);
2954  /*
2955  Look for explicit 'format:image' in filename.
2956  */
2957  *magic='\0';
2958  GetPathComponent(image_info->filename,MagickPath,magic);
2959  if (*magic == '\0')
2960  {
2961  (void) CopyMagickString(magic,image_info->magick,MagickPathExtent);
2962  magick_info=GetMagickInfo(magic,sans_exception);
2963  if ((magick_info != (const MagickInfo *) NULL) &&
2964  (magick_info->format_type == ExplicitFormatType))
2965  image_info->affirm=MagickTrue;
2966  if (frames == 0)
2967  GetPathComponent(image_info->filename,CanonicalPath,component);
2968  else
2969  GetPathComponent(image_info->filename,SubcanonicalPath,component);
2970  (void) CopyMagickString(image_info->filename,component,MagickPathExtent);
2971  }
2972  else
2973  {
2974  const DelegateInfo
2975  *delegate_info;
2976 
2977  /*
2978  User specified image format.
2979  */
2980  LocaleUpper(magic);
2981  magick_info=GetMagickInfo(magic,sans_exception);
2982  delegate_info=(const DelegateInfo *) NULL;
2983  if (magick_info == (const MagickInfo *) NULL)
2984  {
2985  delegate_info=GetDelegateInfo(magic,"*",sans_exception);
2986  if (delegate_info == (const DelegateInfo *) NULL)
2987  delegate_info=GetDelegateInfo("*",magic,sans_exception);
2988  if ((delegate_info == (const DelegateInfo *) NULL) &&
2989  ((*component != '\0') && (IsGlob(component) == MagickFalse)))
2990  {
2991  /*
2992  Retry in case GetMagickInfo loaded a custom module.
2993  */
2994  magick_info=SetImageInfoFromExtension(image_info,component,magic,
2995  sans_exception);
2996  }
2997  }
2998  if (((magick_info != (const MagickInfo *) NULL) ||
2999  (delegate_info != (const DelegateInfo *) NULL)) &&
3000  (IsMagickConflict(magic) == MagickFalse))
3001  {
3002  char *literal = (char *) GetImageRegistry(StringRegistryType,
3003  "filename:literal",exception);
3004  image_info->affirm=MagickTrue;
3005  (void) CopyMagickString(image_info->magick,magic,MagickPathExtent);
3006  GetPathComponent(image_info->filename,CanonicalPath,component);
3007  if (IsStringTrue(literal) != MagickFalse)
3008  GetPathComponent(image_info->filename,SubcanonicalPath,component);
3009  (void) CopyMagickString(image_info->filename,component,
3010  MagickPathExtent);
3011  if (literal != (char *) NULL)
3012  literal=DestroyString(literal);
3013  }
3014  }
3015  sans_exception=DestroyExceptionInfo(sans_exception);
3016  if ((magick_info == (const MagickInfo *) NULL) ||
3017  (GetMagickEndianSupport(magick_info) == MagickFalse))
3018  image_info->endian=UndefinedEndian;
3019  if ((image_info->adjoin != MagickFalse) && (frames > 1))
3020  {
3021  /*
3022  Test for multiple image support (e.g. image%02d.png).
3023  */
3024  (void) InterpretImageFilename(image_info,(Image *) NULL,
3025  image_info->filename,(int) image_info->scene,component,exception);
3026  if ((LocaleCompare(component,image_info->filename) != 0) &&
3027  (strchr(component,'%') == (char *) NULL))
3028  image_info->adjoin=MagickFalse;
3029  }
3030  if ((image_info->adjoin != MagickFalse) && (frames > 0))
3031  {
3032  /*
3033  Some image formats do not support multiple frames per file.
3034  */
3035  magick_info=GetMagickInfo(magic,exception);
3036  if (magick_info != (const MagickInfo *) NULL)
3037  if (GetMagickAdjoin(magick_info) == MagickFalse)
3038  image_info->adjoin=MagickFalse;
3039  }
3040  if (image_info->affirm != MagickFalse)
3041  return(MagickTrue);
3042  if (frames == 0)
3043  {
3044  unsigned char
3045  *magick;
3046 
3047  size_t
3048  magick_size;
3049 
3050  /*
3051  Determine the image format from the first few bytes of the file.
3052  */
3053  magick_size=GetMagicPatternExtent(exception);
3054  if (magick_size == 0)
3055  return(MagickFalse);
3056  image=AcquireImage(image_info,exception);
3057  (void) CopyMagickString(image->filename,image_info->filename,
3058  MagickPathExtent);
3059  sans_exception=AcquireExceptionInfo();
3060  status=OpenBlob(image_info,image,ReadBinaryBlobMode,sans_exception);
3061  sans_exception=DestroyExceptionInfo(sans_exception);
3062  if (status == MagickFalse)
3063  {
3064  image=DestroyImage(image);
3065  return(MagickFalse);
3066  }
3067  if ((IsBlobSeekable(image) == MagickFalse) ||
3068  (IsBlobExempt(image) != MagickFalse))
3069  {
3070  /*
3071  Copy image to seekable temporary file.
3072  */
3073  *component='\0';
3074  status=ImageToFile(image,component,exception);
3075  if (CloseBlob(image) == MagickFalse)
3076  status=MagickFalse;
3077  if (status == MagickFalse)
3078  {
3079  (void) RelinquishUniqueFileResource(component);
3080  image=DestroyImage(image);
3081  return(MagickFalse);
3082  }
3083  SetImageInfoFile(image_info,(FILE *) NULL);
3084  (void) CopyMagickString(image->filename,component,MagickPathExtent);
3085  status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
3086  if (status == MagickFalse)
3087  {
3088  (void) RelinquishUniqueFileResource(component);
3089  image=DestroyImage(image);
3090  return(MagickFalse);
3091  }
3092  (void) CopyMagickString(image_info->filename,component,
3093  MagickPathExtent);
3094  image_info->temporary=MagickTrue;
3095  }
3096  magick=(unsigned char *) AcquireQuantumMemory(1,magick_size);
3097  if (magick == (unsigned char *) NULL)
3098  {
3099  (void) CloseBlob(image);
3100  image=DestroyImage(image);
3101  return(MagickFalse);
3102  }
3103  (void) memset(magick,0,magick_size);
3104  count=ReadBlob(image,magick_size,magick);
3105  (void) SeekBlob(image,-((MagickOffsetType) count),SEEK_CUR);
3106  (void) CloseBlob(image);
3107  image=DestroyImage(image);
3108  /*
3109  Check magic cache.
3110  */
3111  sans_exception=AcquireExceptionInfo();
3112  magic_info=GetMagicInfo(magick,(size_t) count,sans_exception);
3113  magick=(unsigned char *) RelinquishMagickMemory(magick);
3114  if ((magic_info != (const MagicInfo *) NULL) &&
3115  (GetMagicName(magic_info) != (char *) NULL))
3116  {
3117  /*
3118  Try to use magick_info that was determined earlier by the extension
3119  */
3120  if ((magick_info != (const MagickInfo *) NULL) &&
3121  (GetMagickUseExtension(magick_info) != MagickFalse) &&
3122  (LocaleCompare(magick_info->magick_module,GetMagicName(
3123  magic_info)) == 0))
3124  (void) CopyMagickString(image_info->magick,magick_info->name,
3125  MagickPathExtent);
3126  else
3127  {
3128  (void) CopyMagickString(image_info->magick,GetMagicName(
3129  magic_info),MagickPathExtent);
3130  magick_info=GetMagickInfo(image_info->magick,sans_exception);
3131  }
3132  if ((magick_info == (const MagickInfo *) NULL) ||
3133  (GetMagickEndianSupport(magick_info) == MagickFalse))
3134  image_info->endian=UndefinedEndian;
3135  sans_exception=DestroyExceptionInfo(sans_exception);
3136  return(MagickTrue);
3137  }
3138  magick_info=GetMagickInfo(image_info->magick,sans_exception);
3139  if ((magick_info == (const MagickInfo *) NULL) ||
3140  (GetMagickEndianSupport(magick_info) == MagickFalse))
3141  image_info->endian=UndefinedEndian;
3142  sans_exception=DestroyExceptionInfo(sans_exception);
3143  }
3144  return(MagickTrue);
3145 }
3146 ␌
3147 /*
3148 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3149 % %
3150 % %
3151 % %
3152 % S e t I m a g e I n f o B l o b %
3153 % %
3154 % %
3155 % %
3156 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3157 %
3158 % SetImageInfoBlob() sets the image info blob member.
3159 %
3160 % The format of the SetImageInfoBlob method is:
3161 %
3162 % void SetImageInfoBlob(ImageInfo *image_info,const void *blob,
3163 % const size_t length)
3164 %
3165 % A description of each parameter follows:
3166 %
3167 % o image_info: the image info.
3168 %
3169 % o blob: the blob.
3170 %
3171 % o length: the blob length.
3172 %
3173 */
3174 MagickExport void SetImageInfoBlob(ImageInfo *image_info,const void *blob,
3175  const size_t length)
3176 {
3177  assert(image_info != (ImageInfo *) NULL);
3178  assert(image_info->signature == MagickCoreSignature);
3179  if (IsEventLogging() != MagickFalse)
3180  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
3181  image_info->filename);
3182  image_info->blob=(void *) blob;
3183  image_info->length=length;
3184 }
3185 ␌
3186 /*
3187 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3188 % %
3189 % %
3190 % %
3191 % S e t I m a g e I n f o C u s t o m S t r e a m %
3192 % %
3193 % %
3194 % %
3195 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3196 %
3197 % SetImageInfoCustomStream() sets the image info custom stream handlers.
3198 %
3199 % The format of the SetImageInfoCustomStream method is:
3200 %
3201 % void SetImageInfoCustomStream(ImageInfo *image_info,
3202 % CustomStreamInfo *custom_stream)
3203 %
3204 % A description of each parameter follows:
3205 %
3206 % o image_info: the image info.
3207 %
3208 % o custom_stream: your custom stream methods.
3209 %
3210 */
3211 MagickExport void SetImageInfoCustomStream(ImageInfo *image_info,
3212  CustomStreamInfo *custom_stream)
3213 {
3214  assert(image_info != (ImageInfo *) NULL);
3215  assert(image_info->signature == MagickCoreSignature);
3216  if (IsEventLogging() != MagickFalse)
3217  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
3218  image_info->filename);
3219  image_info->custom_stream=(CustomStreamInfo *) custom_stream;
3220 }
3221 ␌
3222 /*
3223 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3224 % %
3225 % %
3226 % %
3227 % S e t I m a g e I n f o F i l e %
3228 % %
3229 % %
3230 % %
3231 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3232 %
3233 % SetImageInfoFile() sets the image info file member.
3234 %
3235 % The format of the SetImageInfoFile method is:
3236 %
3237 % void SetImageInfoFile(ImageInfo *image_info,FILE *file)
3238 %
3239 % A description of each parameter follows:
3240 %
3241 % o image_info: the image info.
3242 %
3243 % o file: the file.
3244 %
3245 */
3246 MagickExport void SetImageInfoFile(ImageInfo *image_info,FILE *file)
3247 {
3248  assert(image_info != (ImageInfo *) NULL);
3249  assert(image_info->signature == MagickCoreSignature);
3250  if (IsEventLogging() != MagickFalse)
3251  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
3252  image_info->filename);
3253  image_info->file=file;
3254 }
3255 ␌
3256 /*
3257 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3258 % %
3259 % %
3260 % %
3261 % S e t I m a g e M a s k %
3262 % %
3263 % %
3264 % %
3265 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3266 %
3267 % SetImageMask() associates a mask with the image. The mask must be the same
3268 % dimensions as the image.
3269 %
3270 % The format of the SetImageMask method is:
3271 %
3272 % MagickBooleanType SetImageMask(Image *image,const PixelMask type,
3273 % const Image *mask,ExceptionInfo *exception)
3274 %
3275 % A description of each parameter follows:
3276 %
3277 % o image: the image.
3278 %
3279 % o type: the mask type, ReadPixelMask or WritePixelMask.
3280 %
3281 % o mask: the image mask.
3282 %
3283 % o exception: return any errors or warnings in this structure.
3284 %
3285 */
3286 MagickExport MagickBooleanType SetImageMask(Image *image,const PixelMask type,
3287  const Image *mask,ExceptionInfo *exception)
3288 {
3289  CacheView
3290  *mask_view,
3291  *image_view;
3292 
3293  MagickBooleanType
3294  status;
3295 
3296  ssize_t
3297  y;
3298 
3299  /*
3300  Set image mask.
3301  */
3302  assert(image != (Image *) NULL);
3303  if (IsEventLogging() != MagickFalse)
3304  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
3305  assert(image->signature == MagickCoreSignature);
3306  image->mask_trait=UndefinedPixelTrait;
3307  if (mask == (const Image *) NULL)
3308  {
3309  switch (type)
3310  {
3311  case ReadPixelMask:
3312  {
3313  image->channels=(ChannelType) ((unsigned int) image->channels &
3314  (unsigned int) ~ReadMaskChannel);
3315  break;
3316  }
3317  case WritePixelMask:
3318  {
3319  image->channels=(ChannelType) ((unsigned int) image->channels &
3320  (unsigned int) ~WriteMaskChannel);
3321  magick_fallthrough;
3322  }
3323  default:
3324  {
3325  image->channels=(ChannelType) ((unsigned int) image->channels &
3326  (unsigned int) ~CompositeMaskChannel);
3327  break;
3328  }
3329  }
3330  return(SyncImagePixelCache(image,exception));
3331  }
3332  switch (type)
3333  {
3334  case ReadPixelMask:
3335  {
3336  image->channels=(ChannelType) (image->channels | ReadMaskChannel);
3337  break;
3338  }
3339  case WritePixelMask:
3340  {
3341  image->channels=(ChannelType) (image->channels | WriteMaskChannel);
3342  break;
3343  }
3344  default:
3345  {
3346  image->channels=(ChannelType) (image->channels | CompositeMaskChannel);
3347  break;
3348  }
3349  }
3350  if (SyncImagePixelCache(image,exception) == MagickFalse)
3351  return(MagickFalse);
3352  status=MagickTrue;
3353  mask_view=AcquireVirtualCacheView(mask,exception);
3354  image_view=AcquireAuthenticCacheView(image,exception);
3355 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3356  #pragma omp parallel for schedule(static) shared(status) \
3357  magick_number_threads(mask,image,image->rows,2)
3358 #endif
3359  for (y=0; y < (ssize_t) image->rows; y++)
3360  {
3361  const Quantum
3362  *magick_restrict p;
3363 
3364  Quantum
3365  *magick_restrict q;
3366 
3367  ssize_t
3368  x;
3369 
3370  if (status == MagickFalse)
3371  continue;
3372  p=GetCacheViewVirtualPixels(mask_view,0,y,mask->columns,1,exception);
3373  q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
3374  if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
3375  {
3376  status=MagickFalse;
3377  continue;
3378  }
3379  for (x=0; x < (ssize_t) image->columns; x++)
3380  {
3381  MagickRealType
3382  intensity;
3383 
3384  intensity=0.0;
3385  if ((x < (ssize_t) mask->columns) && (y < (ssize_t) mask->rows))
3386  intensity=GetPixelIntensity(mask,p);
3387  switch (type)
3388  {
3389  case ReadPixelMask:
3390  {
3391  SetPixelReadMask(image,ClampToQuantum(intensity),q);
3392  break;
3393  }
3394  case WritePixelMask:
3395  {
3396  SetPixelWriteMask(image,ClampToQuantum(intensity),q);
3397  break;
3398  }
3399  default:
3400  {
3401  SetPixelCompositeMask(image,ClampToQuantum(intensity),q);
3402  break;
3403  }
3404  }
3405  p+=(ptrdiff_t) GetPixelChannels(mask);
3406  q+=(ptrdiff_t) GetPixelChannels(image);
3407  }
3408  if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
3409  status=MagickFalse;
3410  }
3411  mask_view=DestroyCacheView(mask_view);
3412  image_view=DestroyCacheView(image_view);
3413  image->mask_trait=UpdatePixelTrait;
3414  return(status);
3415 }
3416 ␌
3417 /*
3418 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3419 % %
3420 % %
3421 % %
3422 % S e t I m a g e R e g i o n M a s k %
3423 % %
3424 % %
3425 % %
3426 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3427 %
3428 % SetImageRegionMask() associates a mask with the image as defined by the
3429 % specified region.
3430 %
3431 % The format of the SetImageRegionMask method is:
3432 %
3433 % MagickBooleanType SetImageRegionMask(Image *image,const PixelMask type,
3434 % const RectangleInfo *region,ExceptionInfo *exception)
3435 %
3436 % A description of each parameter follows:
3437 %
3438 % o image: the image.
3439 %
3440 % o type: the mask type, ReadPixelMask or WritePixelMask.
3441 %
3442 % o geometry: the mask region.
3443 %
3444 % o exception: return any errors or warnings in this structure.
3445 %
3446 */
3447 MagickExport MagickBooleanType SetImageRegionMask(Image *image,
3448  const PixelMask type,const RectangleInfo *region,ExceptionInfo *exception)
3449 {
3450  CacheView
3451  *image_view;
3452 
3453  MagickBooleanType
3454  status;
3455 
3456  ssize_t
3457  y;
3458 
3459  /*
3460  Set image mask as defined by the region.
3461  */
3462  assert(image != (Image *) NULL);
3463  assert(image->signature == MagickCoreSignature);
3464  if (IsEventLogging() != MagickFalse)
3465  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
3466  image->mask_trait=UndefinedPixelTrait;
3467  if (region == (const RectangleInfo *) NULL)
3468  {
3469  switch (type)
3470  {
3471  case ReadPixelMask:
3472  {
3473  image->channels=(ChannelType) ((unsigned int) image->channels &
3474  (unsigned int) ~ReadMaskChannel);
3475  break;
3476  }
3477  case WritePixelMask:
3478  {
3479  image->channels=(ChannelType) ((unsigned int) image->channels &
3480  (unsigned int) ~WriteMaskChannel);
3481  break;
3482  }
3483  default:
3484  {
3485  image->channels=(ChannelType) ((unsigned int) image->channels &
3486  (unsigned int) ~CompositeMaskChannel);
3487  break;
3488  }
3489  }
3490  return(SyncImagePixelCache(image,exception));
3491  }
3492  switch (type)
3493  {
3494  case ReadPixelMask:
3495  {
3496  image->channels=(ChannelType) (image->channels | ReadMaskChannel);
3497  break;
3498  }
3499  case WritePixelMask:
3500  {
3501  image->channels=(ChannelType) (image->channels | WriteMaskChannel);
3502  break;
3503  }
3504  default:
3505  {
3506  image->channels=(ChannelType) (image->channels | CompositeMaskChannel);
3507  break;
3508  }
3509  }
3510  if (SyncImagePixelCache(image,exception) == MagickFalse)
3511  return(MagickFalse);
3512  status=MagickTrue;
3513  image_view=AcquireAuthenticCacheView(image,exception);
3514 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3515  #pragma omp parallel for schedule(static) shared(status) \
3516  magick_number_threads(image,image,image->rows,2)
3517 #endif
3518  for (y=0; y < (ssize_t) image->rows; y++)
3519  {
3520  Quantum
3521  *magick_restrict q;
3522 
3523  ssize_t
3524  x;
3525 
3526  if (status == MagickFalse)
3527  continue;
3528  q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
3529  if (q == (Quantum *) NULL)
3530  {
3531  status=MagickFalse;
3532  continue;
3533  }
3534  for (x=0; x < (ssize_t) image->columns; x++)
3535  {
3536  Quantum
3537  pixel;
3538 
3539  pixel=QuantumRange;
3540  if (((x >= region->x) && (x < (region->x+(ssize_t) region->width))) &&
3541  ((y >= region->y) && (y < (region->y+(ssize_t) region->height))))
3542  pixel=(Quantum) 0;
3543  switch (type)
3544  {
3545  case ReadPixelMask:
3546  {
3547  SetPixelReadMask(image,pixel,q);
3548  break;
3549  }
3550  case WritePixelMask:
3551  {
3552  SetPixelWriteMask(image,pixel,q);
3553  break;
3554  }
3555  default:
3556  {
3557  SetPixelCompositeMask(image,pixel,q);
3558  break;
3559  }
3560  }
3561  q+=(ptrdiff_t) GetPixelChannels(image);
3562  }
3563  if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
3564  status=MagickFalse;
3565  }
3566  image->mask_trait=UpdatePixelTrait;
3567  image_view=DestroyCacheView(image_view);
3568  return(status);
3569 }
3570 ␌
3571 /*
3572 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3573 % %
3574 % %
3575 % %
3576 % S e t I m a g e V i r t u a l P i x e l M e t h o d %
3577 % %
3578 % %
3579 % %
3580 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3581 %
3582 % SetImageVirtualPixelMethod() sets the "virtual pixels" method for the
3583 % image and returns the previous setting. A virtual pixel is any pixel access
3584 % that is outside the boundaries of the image cache.
3585 %
3586 % The format of the SetImageVirtualPixelMethod() method is:
3587 %
3588 % VirtualPixelMethod SetImageVirtualPixelMethod(Image *image,
3589 % const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
3590 %
3591 % A description of each parameter follows:
3592 %
3593 % o image: the image.
3594 %
3595 % o virtual_pixel_method: choose the type of virtual pixel.
3596 %
3597 % o exception: return any errors or warnings in this structure.
3598 %
3599 */
3600 MagickExport VirtualPixelMethod SetImageVirtualPixelMethod(Image *image,
3601  const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
3602 {
3603  assert(image != (const Image *) NULL);
3604  assert(image->signature == MagickCoreSignature);
3605  if (IsEventLogging() != MagickFalse)
3606  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3607  return(SetPixelCacheVirtualMethod(image,virtual_pixel_method,exception));
3608 }
3609 ␌
3610 /*
3611 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3612 % %
3613 % %
3614 % %
3615 % S m u s h I m a g e s %
3616 % %
3617 % %
3618 % %
3619 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3620 %
3621 % SmushImages() takes all images from the current image pointer to the end
3622 % of the image list and smushes them to each other top-to-bottom if the
3623 % stack parameter is true, otherwise left-to-right.
3624 %
3625 % The current gravity setting now effects how the image is justified in the
3626 % final image.
3627 %
3628 % The format of the SmushImages method is:
3629 %
3630 % Image *SmushImages(const Image *images,const MagickBooleanType stack,
3631 % ExceptionInfo *exception)
3632 %
3633 % A description of each parameter follows:
3634 %
3635 % o images: the image sequence.
3636 %
3637 % o stack: A value other than 0 stacks the images top-to-bottom.
3638 %
3639 % o offset: minimum distance in pixels between images.
3640 %
3641 % o exception: return any errors or warnings in this structure.
3642 %
3643 */
3644 
3645 static ssize_t SmushXGap(const Image *smush_image,const Image *images,
3646  const ssize_t offset,ExceptionInfo *exception)
3647 {
3648  CacheView
3649  *left_view,
3650  *right_view;
3651 
3652  const Image
3653  *left_image,
3654  *right_image;
3655 
3657  left_geometry,
3658  right_geometry;
3659 
3660  const Quantum
3661  *p;
3662 
3663  ssize_t
3664  i,
3665  y;
3666 
3667  size_t
3668  gap;
3669 
3670  ssize_t
3671  x;
3672 
3673  if (images->previous == (Image *) NULL)
3674  return(0);
3675  right_image=images;
3676  SetGeometry(smush_image,&right_geometry);
3677  GravityAdjustGeometry(right_image->columns,right_image->rows,
3678  right_image->gravity,&right_geometry);
3679  left_image=images->previous;
3680  SetGeometry(smush_image,&left_geometry);
3681  GravityAdjustGeometry(left_image->columns,left_image->rows,
3682  left_image->gravity,&left_geometry);
3683  gap=right_image->columns;
3684  left_view=AcquireVirtualCacheView(left_image,exception);
3685  right_view=AcquireVirtualCacheView(right_image,exception);
3686  for (y=0; y < (ssize_t) smush_image->rows; y++)
3687  {
3688  for (x=(ssize_t) left_image->columns-1; x > 0; x--)
3689  {
3690  p=GetCacheViewVirtualPixels(left_view,x,left_geometry.y+y,1,1,exception);
3691  if ((p == (const Quantum *) NULL) ||
3692  (GetPixelAlpha(left_image,p) != TransparentAlpha) ||
3693  (((ssize_t) left_image->columns-x-1) >= (ssize_t) gap))
3694  break;
3695  }
3696  i=(ssize_t) left_image->columns-x-1;
3697  for (x=0; x < (ssize_t) right_image->columns; x++)
3698  {
3699  p=GetCacheViewVirtualPixels(right_view,x,right_geometry.y+y,1,1,
3700  exception);
3701  if ((p == (const Quantum *) NULL) ||
3702  (GetPixelAlpha(right_image,p) != TransparentAlpha) ||
3703  ((x+i) >= (ssize_t) gap))
3704  break;
3705  }
3706  if ((x+i) < (ssize_t) gap)
3707  gap=(size_t) (x+i);
3708  }
3709  right_view=DestroyCacheView(right_view);
3710  left_view=DestroyCacheView(left_view);
3711  if (y < (ssize_t) smush_image->rows)
3712  return(offset);
3713  return((ssize_t) gap-offset);
3714 }
3715 
3716 static ssize_t SmushYGap(const Image *smush_image,const Image *images,
3717  const ssize_t offset,ExceptionInfo *exception)
3718 {
3719  CacheView
3720  *bottom_view,
3721  *top_view;
3722 
3723  const Image
3724  *bottom_image,
3725  *top_image;
3726 
3728  bottom_geometry,
3729  top_geometry;
3730 
3731  const Quantum
3732  *p;
3733 
3734  ssize_t
3735  i,
3736  x;
3737 
3738  size_t
3739  gap;
3740 
3741  ssize_t
3742  y;
3743 
3744  if (images->previous == (Image *) NULL)
3745  return(0);
3746  bottom_image=images;
3747  SetGeometry(smush_image,&bottom_geometry);
3748  GravityAdjustGeometry(bottom_image->columns,bottom_image->rows,
3749  bottom_image->gravity,&bottom_geometry);
3750  top_image=images->previous;
3751  SetGeometry(smush_image,&top_geometry);
3752  GravityAdjustGeometry(top_image->columns,top_image->rows,top_image->gravity,
3753  &top_geometry);
3754  gap=bottom_image->rows;
3755  top_view=AcquireVirtualCacheView(top_image,exception);
3756  bottom_view=AcquireVirtualCacheView(bottom_image,exception);
3757  for (x=0; x < (ssize_t) smush_image->columns; x++)
3758  {
3759  for (y=(ssize_t) top_image->rows-1; y > 0; y--)
3760  {
3761  p=GetCacheViewVirtualPixels(top_view,top_geometry.x+x,y,1,1,exception);
3762  if ((p == (const Quantum *) NULL) ||
3763  (GetPixelAlpha(top_image,p) != TransparentAlpha) ||
3764  (((ssize_t) top_image->rows-y-1) >= (ssize_t) gap))
3765  break;
3766  }
3767  i=(ssize_t) top_image->rows-y-1;
3768  for (y=0; y < (ssize_t) bottom_image->rows; y++)
3769  {
3770  p=GetCacheViewVirtualPixels(bottom_view,bottom_geometry.x+x,y,1,1,
3771  exception);
3772  if ((p == (const Quantum *) NULL) ||
3773  (GetPixelAlpha(bottom_image,p) != TransparentAlpha) ||
3774  ((y+i) >= (ssize_t) gap))
3775  break;
3776  }
3777  if ((y+i) < (ssize_t) gap)
3778  gap=(size_t) (y+i);
3779  }
3780  bottom_view=DestroyCacheView(bottom_view);
3781  top_view=DestroyCacheView(top_view);
3782  if (x < (ssize_t) smush_image->columns)
3783  return(offset);
3784  return((ssize_t) gap-offset);
3785 }
3786 
3787 MagickExport Image *SmushImages(const Image *images,
3788  const MagickBooleanType stack,const ssize_t offset,ExceptionInfo *exception)
3789 {
3790 #define SmushImageTag "Smush/Image"
3791 
3792  const Image
3793  *image;
3794 
3795  Image
3796  *smush_image;
3797 
3798  MagickBooleanType
3799  proceed,
3800  status;
3801 
3802  MagickOffsetType
3803  n;
3804 
3805  PixelTrait
3806  alpha_trait;
3807 
3809  geometry;
3810 
3811  const Image
3812  *next;
3813 
3814  size_t
3815  height,
3816  number_images,
3817  width;
3818 
3819  ssize_t
3820  x_offset,
3821  y_offset;
3822 
3823  /*
3824  Compute maximum area of smushed area.
3825  */
3826  assert(images != (Image *) NULL);
3827  assert(images->signature == MagickCoreSignature);
3828  assert(exception != (ExceptionInfo *) NULL);
3829  assert(exception->signature == MagickCoreSignature);
3830  if (IsEventLogging() != MagickFalse)
3831  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
3832  image=images;
3833  alpha_trait=image->alpha_trait;
3834  number_images=1;
3835  width=image->columns;
3836  height=image->rows;
3837  next=GetNextImageInList(image);
3838  for ( ; next != (Image *) NULL; next=GetNextImageInList(next))
3839  {
3840  if (next->alpha_trait != UndefinedPixelTrait)
3841  alpha_trait=BlendPixelTrait;
3842  number_images++;
3843  if (stack != MagickFalse)
3844  {
3845  if (next->columns > width)
3846  width=next->columns;
3847  height+=next->rows;
3848  if (next->previous != (Image *) NULL)
3849  height=(size_t) MagickMax((ssize_t) height+offset,0U);
3850  continue;
3851  }
3852  width+=next->columns;
3853  if (next->previous != (Image *) NULL)
3854  width=(size_t) MagickMax((ssize_t) width+offset,0U);
3855  if (next->rows > height)
3856  height=next->rows;
3857  }
3858  /*
3859  Smush images.
3860  */
3861  smush_image=CloneImage(image,width,height,MagickTrue,exception);
3862  if (smush_image == (Image *) NULL)
3863  return((Image *) NULL);
3864  if (SetImageStorageClass(smush_image,DirectClass,exception) == MagickFalse)
3865  {
3866  smush_image=DestroyImage(smush_image);
3867  return((Image *) NULL);
3868  }
3869  smush_image->alpha_trait=alpha_trait;
3870  (void) SetImageBackgroundColor(smush_image,exception);
3871  status=MagickTrue;
3872  x_offset=0;
3873  y_offset=0;
3874  for (n=0; n < (MagickOffsetType) number_images; n++)
3875  {
3876  SetGeometry(smush_image,&geometry);
3877  GravityAdjustGeometry(image->columns,image->rows,image->gravity,&geometry);
3878  if (stack != MagickFalse)
3879  {
3880  x_offset-=geometry.x;
3881  y_offset-=SmushYGap(smush_image,image,offset,exception);
3882  }
3883  else
3884  {
3885  x_offset-=SmushXGap(smush_image,image,offset,exception);
3886  y_offset-=geometry.y;
3887  }
3888  status=CompositeImage(smush_image,image,OverCompositeOp,MagickTrue,x_offset,
3889  y_offset,exception);
3890  proceed=SetImageProgress(image,SmushImageTag,n,number_images);
3891  if (proceed == MagickFalse)
3892  break;
3893  if (stack == MagickFalse)
3894  {
3895  x_offset+=(ssize_t) image->columns;
3896  y_offset=0;
3897  }
3898  else
3899  {
3900  x_offset=0;
3901  y_offset+=(ssize_t) image->rows;
3902  }
3903  image=GetNextImageInList(image);
3904  }
3905  if (stack == MagickFalse)
3906  smush_image->columns=(size_t) x_offset;
3907  else
3908  smush_image->rows=(size_t) y_offset;
3909  if (status == MagickFalse)
3910  smush_image=DestroyImage(smush_image);
3911  return(smush_image);
3912 }
3913 ␌
3914 /*
3915 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3916 % %
3917 % %
3918 % %
3919 % S t r i p I m a g e %
3920 % %
3921 % %
3922 % %
3923 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3924 %
3925 % StripImage() strips an image of all profiles and comments.
3926 %
3927 % The format of the StripImage method is:
3928 %
3929 % MagickBooleanType StripImage(Image *image,ExceptionInfo *exception)
3930 %
3931 % A description of each parameter follows:
3932 %
3933 % o image: the image.
3934 %
3935 % o exception: return any errors or warnings in this structure.
3936 %
3937 */
3938 MagickExport MagickBooleanType StripImage(Image *image,
3939  ExceptionInfo *magick_unused(exception))
3940 {
3941  MagickBooleanType
3942  status;
3943 
3944  magick_unreferenced(exception);
3945  assert(image != (Image *) NULL);
3946  if (IsEventLogging() != MagickFalse)
3947  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
3948  DestroyImageProfiles(image);
3949  (void) DeleteImageProperty(image,"comment");
3950  (void) DeleteImageProperty(image,"date:create");
3951  (void) DeleteImageProperty(image,"date:modify");
3952  (void) DeleteImageProperty(image,"date:timestamp");
3953  status=SetImageArtifact(image,"png:exclude-chunk",
3954  "bKGD,caNv,cHRM,eXIf,gAMA,iCCP,iTXt,pHYs,sRGB,tEXt,zCCP,zTXt,date");
3955  return(status);
3956 }
3957 ␌
3958 /*
3959 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3960 % %
3961 % %
3962 % %
3963 + S y n c I m a g e %
3964 % %
3965 % %
3966 % %
3967 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3968 %
3969 % SyncImage() initializes the red, green, and blue intensities of each pixel
3970 % as defined by the colormap index.
3971 %
3972 % The format of the SyncImage method is:
3973 %
3974 % MagickBooleanType SyncImage(Image *image,ExceptionInfo *exception)
3975 %
3976 % A description of each parameter follows:
3977 %
3978 % o image: the image.
3979 %
3980 % o exception: return any errors or warnings in this structure.
3981 %
3982 */
3983 
3984 static inline Quantum PushColormapIndex(Image *image,const Quantum index,
3985  MagickBooleanType *range_exception)
3986 {
3987  if ((size_t) index < image->colors)
3988  return(index);
3989  *range_exception=MagickTrue;
3990  return((Quantum) 0);
3991 }
3992 
3993 MagickExport MagickBooleanType SyncImage(Image *image,ExceptionInfo *exception)
3994 {
3995  CacheView
3996  *image_view;
3997 
3998  MagickBooleanType
3999  range_exception,
4000  status,
4001  taint;
4002 
4003  ssize_t
4004  y;
4005 
4006  assert(image != (Image *) NULL);
4007  assert(image->signature == MagickCoreSignature);
4008  if (IsEventLogging() != MagickFalse)
4009  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
4010  if (image->ping != MagickFalse)
4011  return(MagickTrue);
4012  if (image->storage_class != PseudoClass)
4013  return(MagickFalse);
4014  assert(image->colormap != (PixelInfo *) NULL);
4015  range_exception=MagickFalse;
4016  status=MagickTrue;
4017  taint=image->taint;
4018  image_view=AcquireAuthenticCacheView(image,exception);
4019 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4020  #pragma omp parallel for schedule(static) shared(range_exception,status) \
4021  magick_number_threads(image,image,image->rows,2)
4022 #endif
4023  for (y=0; y < (ssize_t) image->rows; y++)
4024  {
4025  Quantum
4026  index;
4027 
4028  Quantum
4029  *magick_restrict q;
4030 
4031  ssize_t
4032  x;
4033 
4034  if (status == MagickFalse)
4035  continue;
4036  q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
4037  if (q == (Quantum *) NULL)
4038  {
4039  status=MagickFalse;
4040  continue;
4041  }
4042  for (x=0; x < (ssize_t) image->columns; x++)
4043  {
4044  index=PushColormapIndex(image,GetPixelIndex(image,q),&range_exception);
4045  SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q);
4046  q+=(ptrdiff_t) GetPixelChannels(image);
4047  }
4048  if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
4049  status=MagickFalse;
4050  }
4051  image_view=DestroyCacheView(image_view);
4052  image->taint=taint;
4053  if ((image->ping == MagickFalse) && (range_exception != MagickFalse))
4054  (void) ThrowMagickException(exception,GetMagickModule(),
4055  CorruptImageWarning,"InvalidColormapIndex","`%s'",image->filename);
4056  return(status);
4057 }
4058 ␌
4059 /*
4060 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4061 % %
4062 % %
4063 % %
4064 % S y n c I m a g e S e t t i n g s %
4065 % %
4066 % %
4067 % %
4068 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4069 %
4070 % SyncImageSettings() syncs any image_info global options into per-image
4071 % attributes.
4072 %
4073 % Note: in IMv6 free form 'options' were always mapped into 'artifacts', so
4074 % that operations and coders can find such settings. In IMv7 if a desired
4075 % per-image artifact is not set, then it will directly look for a global
4076 % option as a fallback, as such this copy is no longer needed, only the
4077 % link set up.
4078 %
4079 % The format of the SyncImageSettings method is:
4080 %
4081 % MagickBooleanType SyncImageSettings(const ImageInfo *image_info,
4082 % Image *image,ExceptionInfo *exception)
4083 % MagickBooleanType SyncImagesSettings(const ImageInfo *image_info,
4084 % Image *image,ExceptionInfo *exception)
4085 %
4086 % A description of each parameter follows:
4087 %
4088 % o image_info: the image info.
4089 %
4090 % o image: the image.
4091 %
4092 % o exception: return any errors or warnings in this structure.
4093 %
4094 */
4095 
4096 MagickExport MagickBooleanType SyncImagesSettings(ImageInfo *image_info,
4097  Image *images,ExceptionInfo *exception)
4098 {
4099  Image
4100  *image;
4101 
4102  assert(image_info != (const ImageInfo *) NULL);
4103  assert(image_info->signature == MagickCoreSignature);
4104  assert(images != (Image *) NULL);
4105  assert(images->signature == MagickCoreSignature);
4106  if (IsEventLogging() != MagickFalse)
4107  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
4108  image=images;
4109  for ( ; image != (Image *) NULL; image=GetNextImageInList(image))
4110  (void) SyncImageSettings(image_info,image,exception);
4111  (void) DeleteImageOption(image_info,"page");
4112  return(MagickTrue);
4113 }
4114 
4115 MagickExport MagickBooleanType SyncImageSettings(const ImageInfo *image_info,
4116  Image *image,ExceptionInfo *exception)
4117 {
4118  const char
4119  *option;
4120 
4121  GeometryInfo
4122  geometry_info;
4123 
4124  MagickStatusType
4125  flags;
4126 
4127  ResolutionType
4128  units;
4129 
4130  /*
4131  Sync image options.
4132  */
4133  assert(image_info != (const ImageInfo *) NULL);
4134  assert(image_info->signature == MagickCoreSignature);
4135  assert(image != (Image *) NULL);
4136  assert(image->signature == MagickCoreSignature);
4137  if (IsEventLogging() != MagickFalse)
4138  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4139  option=GetImageOption(image_info,"background");
4140  if (option != (const char *) NULL)
4141  (void) QueryColorCompliance(option,AllCompliance,&image->background_color,
4142  exception);
4143  option=GetImageOption(image_info,"black-point-compensation");
4144  if (option != (const char *) NULL)
4145  image->black_point_compensation=(MagickBooleanType) ParseCommandOption(
4146  MagickBooleanOptions,MagickFalse,option);
4147  option=GetImageOption(image_info,"blue-primary");
4148  if (option != (const char *) NULL)
4149  {
4150  flags=ParseGeometry(option,&geometry_info);
4151  if ((flags & RhoValue) != 0)
4152  image->chromaticity.blue_primary.x=geometry_info.rho;
4153  image->chromaticity.blue_primary.y=image->chromaticity.blue_primary.x;
4154  if ((flags & SigmaValue) != 0)
4155  image->chromaticity.blue_primary.y=geometry_info.sigma;
4156  }
4157  option=GetImageOption(image_info,"bordercolor");
4158  if (option != (const char *) NULL)
4159  (void) QueryColorCompliance(option,AllCompliance,&image->border_color,
4160  exception);
4161  /* FUTURE: do not sync compose to per-image compose setting here */
4162  option=GetImageOption(image_info,"compose");
4163  if (option != (const char *) NULL)
4164  image->compose=(CompositeOperator) ParseCommandOption(MagickComposeOptions,
4165  MagickFalse,option);
4166  /* -- */
4167  option=GetImageOption(image_info,"compress");
4168  if (option != (const char *) NULL)
4169  image->compression=(CompressionType) ParseCommandOption(
4170  MagickCompressOptions,MagickFalse,option);
4171  option=GetImageOption(image_info,"debug");
4172  if (option != (const char *) NULL)
4173  image->debug=(MagickBooleanType) ParseCommandOption(MagickBooleanOptions,
4174  MagickFalse,option);
4175  option=GetImageOption(image_info,"density");
4176  if (option != (const char *) NULL)
4177  {
4178  flags=ParseGeometry(option,&geometry_info);
4179  if ((flags & RhoValue) != 0)
4180  image->resolution.x=geometry_info.rho;
4181  image->resolution.y=image->resolution.x;
4182  if ((flags & SigmaValue) != 0)
4183  image->resolution.y=geometry_info.sigma;
4184  }
4185  option=GetImageOption(image_info,"depth");
4186  if (option != (const char *) NULL)
4187  image->depth=StringToUnsignedLong(option);
4188  option=GetImageOption(image_info,"endian");
4189  if (option != (const char *) NULL)
4190  image->endian=(EndianType) ParseCommandOption(MagickEndianOptions,
4191  MagickFalse,option);
4192  option=GetImageOption(image_info,"filter");
4193  if (option != (const char *) NULL)
4194  image->filter=(FilterType) ParseCommandOption(MagickFilterOptions,
4195  MagickFalse,option);
4196  option=GetImageOption(image_info,"fuzz");
4197  if (option != (const char *) NULL)
4198  image->fuzz=StringToDoubleInterval(option,(double) QuantumRange+1.0);
4199  option=GetImageOption(image_info,"gravity");
4200  if (option != (const char *) NULL)
4201  image->gravity=(GravityType) ParseCommandOption(MagickGravityOptions,
4202  MagickFalse,option);
4203  option=GetImageOption(image_info,"green-primary");
4204  if (option != (const char *) NULL)
4205  {
4206  flags=ParseGeometry(option,&geometry_info);
4207  if ((flags & RhoValue) != 0)
4208  image->chromaticity.green_primary.x=geometry_info.rho;
4209  image->chromaticity.green_primary.y=image->chromaticity.green_primary.x;
4210  if ((flags & SigmaValue) != 0)
4211  image->chromaticity.green_primary.y=geometry_info.sigma;
4212  }
4213  option=GetImageOption(image_info,"intent");
4214  if (option != (const char *) NULL)
4215  image->rendering_intent=(RenderingIntent) ParseCommandOption(
4216  MagickIntentOptions,MagickFalse,option);
4217  option=GetImageOption(image_info,"intensity");
4218  if (option != (const char *) NULL)
4219  image->intensity=(PixelIntensityMethod) ParseCommandOption(
4220  MagickPixelIntensityOptions,MagickFalse,option);
4221  option=GetImageOption(image_info,"interlace");
4222  if (option != (const char *) NULL)
4223  image->interlace=(InterlaceType) ParseCommandOption(MagickInterlaceOptions,
4224  MagickFalse,option);
4225  option=GetImageOption(image_info,"interpolate");
4226  if (option != (const char *) NULL)
4227  image->interpolate=(PixelInterpolateMethod) ParseCommandOption(
4228  MagickInterpolateOptions,MagickFalse,option);
4229  option=GetImageOption(image_info,"loop");
4230  if (option != (const char *) NULL)
4231  image->iterations=StringToUnsignedLong(option);
4232  option=GetImageOption(image_info,"mattecolor");
4233  if (option != (const char *) NULL)
4234  (void) QueryColorCompliance(option,AllCompliance,&image->matte_color,
4235  exception);
4236  option=GetImageOption(image_info,"orient");
4237  if (option != (const char *) NULL)
4238  image->orientation=(OrientationType) ParseCommandOption(
4239  MagickOrientationOptions,MagickFalse,option);
4240  option=GetImageOption(image_info,"page");
4241  if (option != (const char *) NULL)
4242  {
4243  char
4244  *geometry;
4245 
4246  geometry=GetPageGeometry(option);
4247  flags=ParseAbsoluteGeometry(geometry,&image->page);
4248  geometry=DestroyString(geometry);
4249  }
4250  option=GetImageOption(image_info,"quality");
4251  if (option != (const char *) NULL)
4252  image->quality=StringToUnsignedLong(option);
4253  option=GetImageOption(image_info,"red-primary");
4254  if (option != (const char *) NULL)
4255  {
4256  flags=ParseGeometry(option,&geometry_info);
4257  if ((flags & RhoValue) != 0)
4258  image->chromaticity.red_primary.x=geometry_info.rho;
4259  image->chromaticity.red_primary.y=image->chromaticity.red_primary.x;
4260  if ((flags & SigmaValue) != 0)
4261  image->chromaticity.red_primary.y=geometry_info.sigma;
4262  }
4263  if (image_info->quality != UndefinedCompressionQuality)
4264  image->quality=image_info->quality;
4265  option=GetImageOption(image_info,"scene");
4266  if (option != (const char *) NULL)
4267  image->scene=StringToUnsignedLong(option);
4268  option=GetImageOption(image_info,"taint");
4269  if (option != (const char *) NULL)
4270  image->taint=(MagickBooleanType) ParseCommandOption(MagickBooleanOptions,
4271  MagickFalse,option);
4272  option=GetImageOption(image_info,"tile-offset");
4273  if (option != (const char *) NULL)
4274  {
4275  char
4276  *geometry;
4277 
4278  geometry=GetPageGeometry(option);
4279  flags=ParseAbsoluteGeometry(geometry,&image->tile_offset);
4280  geometry=DestroyString(geometry);
4281  }
4282  option=GetImageOption(image_info,"transparent-color");
4283  if (option != (const char *) NULL)
4284  (void) QueryColorCompliance(option,AllCompliance,&image->transparent_color,
4285  exception);
4286  option=GetImageOption(image_info,"type");
4287  if (option != (const char *) NULL)
4288  image->type=(ImageType) ParseCommandOption(MagickTypeOptions,MagickFalse,
4289  option);
4290  option=GetImageOption(image_info,"units");
4291  units=image_info->units;
4292  if (option != (const char *) NULL)
4293  units=(ResolutionType) ParseCommandOption(MagickResolutionOptions,
4294  MagickFalse,option);
4295  if (units != UndefinedResolution)
4296  {
4297  if (image->units != units)
4298  switch (image->units)
4299  {
4300  case PixelsPerInchResolution:
4301  {
4302  if (units == PixelsPerCentimeterResolution)
4303  {
4304  image->resolution.x/=2.54;
4305  image->resolution.y/=2.54;
4306  }
4307  break;
4308  }
4309  case PixelsPerCentimeterResolution:
4310  {
4311  if (units == PixelsPerInchResolution)
4312  {
4313  image->resolution.x=(double) ((size_t) (100.0*2.54*
4314  image->resolution.x+0.5))/100.0;
4315  image->resolution.y=(double) ((size_t) (100.0*2.54*
4316  image->resolution.y+0.5))/100.0;
4317  }
4318  break;
4319  }
4320  default:
4321  break;
4322  }
4323  image->units=units;
4324  option=GetImageOption(image_info,"density");
4325  if (option != (const char *) NULL)
4326  {
4327  flags=ParseGeometry(option,&geometry_info);
4328  if ((flags & RhoValue) != 0)
4329  image->resolution.x=geometry_info.rho;
4330  image->resolution.y=image->resolution.x;
4331  if ((flags & SigmaValue) != 0)
4332  image->resolution.y=geometry_info.sigma;
4333  }
4334  }
4335  option=GetImageOption(image_info,"virtual-pixel");
4336  if (option != (const char *) NULL)
4337  (void) SetImageVirtualPixelMethod(image,(VirtualPixelMethod)
4338  ParseCommandOption(MagickVirtualPixelOptions,MagickFalse,option),
4339  exception);
4340  option=GetImageOption(image_info,"white-point");
4341  if (option != (const char *) NULL)
4342  {
4343  flags=ParseGeometry(option,&geometry_info);
4344  if ((flags & RhoValue) != 0)
4345  image->chromaticity.white_point.x=geometry_info.rho;
4346  image->chromaticity.white_point.y=image->chromaticity.white_point.x;
4347  if ((flags & SigmaValue) != 0)
4348  image->chromaticity.white_point.y=geometry_info.sigma;
4349  }
4350  /*
4351  Pointer to allow the lookup of pre-image artifact will fallback to a global
4352  option setting/define. This saves a lot of duplication of global options
4353  into per-image artifacts, while ensuring only specifically set per-image
4354  artifacts are preserved when parenthesis ends.
4355  */
4356  if (image->image_info != (ImageInfo *) NULL)
4357  image->image_info=DestroyImageInfo(image->image_info);
4358  image->image_info=CloneImageInfo(image_info);
4359  return(MagickTrue);
4360 }
Definition: image.h:132