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