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