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