]> granicus.if.org Git - imagemagick/blob - MagickCore/image.c
Removed 'unused' zero property from ImageInfo.
[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         ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
847       (void) CopyMagickMemory(clone_image->colormap,image->colormap,length*
848         sizeof(*clone_image->colormap));
849     }
850   clone_image->image_info=CloneImageInfo(image->image_info);
851   (void) CloneImageProfiles(clone_image,image);
852   (void) CloneImageProperties(clone_image,image);
853   (void) CloneImageArtifacts(clone_image,image);
854   GetTimerInfo(&clone_image->timer);
855   if (image->ascii85 != (void *) NULL)
856     Ascii85Initialize(clone_image);
857   clone_image->magick_columns=image->magick_columns;
858   clone_image->magick_rows=image->magick_rows;
859   clone_image->type=image->type;
860   clone_image->channel_mask=image->channel_mask;
861   clone_image->channel_map=ClonePixelChannelMap(image->channel_map);
862   (void) CopyMagickString(clone_image->magick_filename,image->magick_filename,
863     MagickPathExtent);
864   (void) CopyMagickString(clone_image->magick,image->magick,MagickPathExtent);
865   (void) CopyMagickString(clone_image->filename,image->filename,
866     MagickPathExtent);
867   clone_image->progress_monitor=image->progress_monitor;
868   clone_image->client_data=image->client_data;
869   clone_image->reference_count=1;
870   clone_image->next=image->next;
871   clone_image->previous=image->previous;
872   clone_image->list=NewImageList();
873   if (detach == MagickFalse)
874     clone_image->blob=ReferenceBlob(image->blob);
875   else
876     {
877       clone_image->next=NewImageList();
878       clone_image->previous=NewImageList();
879       clone_image->blob=CloneBlobInfo((BlobInfo *) NULL);
880     }
881   clone_image->ping=image->ping;
882   clone_image->debug=IsEventLogging();
883   clone_image->semaphore=AcquireSemaphoreInfo();
884   if ((columns == 0) || (rows == 0))
885     {
886       if (image->montage != (char *) NULL)
887         (void) CloneString(&clone_image->montage,image->montage);
888       if (image->directory != (char *) NULL)
889         (void) CloneString(&clone_image->directory,image->directory);
890       clone_image->cache=ReferencePixelCache(image->cache);
891       return(clone_image);
892     }
893   scale=1.0;
894   if (image->columns != 0)
895     scale=(double) columns/(double) image->columns;
896   clone_image->page.width=(size_t) floor(scale*image->page.width+0.5);
897   clone_image->page.x=(ssize_t) ceil(scale*image->page.x-0.5);
898   clone_image->tile_offset.x=(ssize_t) ceil(scale*image->tile_offset.x-0.5);
899   scale=1.0;
900   if (image->rows != 0)
901     scale=(double) rows/(double) image->rows;
902   clone_image->page.height=(size_t) floor(scale*image->page.height+0.5);
903   clone_image->page.y=(ssize_t) ceil(scale*image->page.y-0.5);
904   clone_image->tile_offset.y=(ssize_t) ceil(scale*image->tile_offset.y-0.5);
905   clone_image->columns=columns;
906   clone_image->rows=rows;
907   clone_image->cache=ClonePixelCache(image->cache);
908   return(clone_image);
909 }
910 \f
911 /*
912 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
913 %                                                                             %
914 %                                                                             %
915 %                                                                             %
916 %   C l o n e I m a g e I n f o                                               %
917 %                                                                             %
918 %                                                                             %
919 %                                                                             %
920 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
921 %
922 %  CloneImageInfo() makes a copy of the given image info structure.  If
923 %  NULL is specified, a new image info structure is created initialized to
924 %  default values.
925 %
926 %  The format of the CloneImageInfo method is:
927 %
928 %      ImageInfo *CloneImageInfo(const ImageInfo *image_info)
929 %
930 %  A description of each parameter follows:
931 %
932 %    o image_info: the image info.
933 %
934 */
935 MagickExport ImageInfo *CloneImageInfo(const ImageInfo *image_info)
936 {
937   ImageInfo
938     *clone_info;
939
940   clone_info=AcquireImageInfo();
941   if (image_info == (ImageInfo *) NULL)
942     return(clone_info);
943   clone_info->compression=image_info->compression;
944   clone_info->temporary=image_info->temporary;
945   clone_info->adjoin=image_info->adjoin;
946   clone_info->antialias=image_info->antialias;
947   clone_info->scene=image_info->scene;
948   clone_info->number_scenes=image_info->number_scenes;
949   clone_info->depth=image_info->depth;
950   (void) CloneString(&clone_info->size,image_info->size);
951   (void) CloneString(&clone_info->extract,image_info->extract);
952   (void) CloneString(&clone_info->scenes,image_info->scenes);
953   (void) CloneString(&clone_info->page,image_info->page);
954   clone_info->interlace=image_info->interlace;
955   clone_info->endian=image_info->endian;
956   clone_info->units=image_info->units;
957   clone_info->quality=image_info->quality;
958   (void) CloneString(&clone_info->sampling_factor,image_info->sampling_factor);
959   (void) CloneString(&clone_info->server_name,image_info->server_name);
960   (void) CloneString(&clone_info->font,image_info->font);
961   (void) CloneString(&clone_info->texture,image_info->texture);
962   (void) CloneString(&clone_info->density,image_info->density);
963   clone_info->pointsize=image_info->pointsize;
964   clone_info->fuzz=image_info->fuzz;
965   clone_info->alpha_color=image_info->alpha_color;
966   clone_info->background_color=image_info->background_color;
967   clone_info->border_color=image_info->border_color;
968   clone_info->transparent_color=image_info->transparent_color;
969   clone_info->dither=image_info->dither;
970   clone_info->monochrome=image_info->monochrome;
971   clone_info->colorspace=image_info->colorspace;
972   clone_info->type=image_info->type;
973   clone_info->orientation=image_info->orientation;
974   clone_info->preview_type=image_info->preview_type;
975   clone_info->group=image_info->group;
976   clone_info->ping=image_info->ping;
977   clone_info->verbose=image_info->verbose;
978   clone_info->progress_monitor=image_info->progress_monitor;
979   clone_info->client_data=image_info->client_data;
980   clone_info->cache=image_info->cache;
981   if (image_info->cache != (void *) NULL)
982     clone_info->cache=ReferencePixelCache(image_info->cache);
983   if (image_info->profile != (void *) NULL)
984     clone_info->profile=(void *) CloneStringInfo((StringInfo *)
985       image_info->profile);
986   SetImageInfoFile(clone_info,image_info->file);
987   SetImageInfoBlob(clone_info,image_info->blob,image_info->length);
988   clone_info->stream=image_info->stream;
989   (void) CopyMagickString(clone_info->magick,image_info->magick,
990     MagickPathExtent);
991   (void) CopyMagickString(clone_info->unique,image_info->unique,
992     MagickPathExtent);
993   (void) CopyMagickString(clone_info->filename,image_info->filename,
994     MagickPathExtent);
995   clone_info->channel=image_info->channel;
996   (void) CloneImageOptions(clone_info,image_info);
997   clone_info->debug=IsEventLogging();
998   clone_info->signature=image_info->signature;
999   return(clone_info);
1000 }
1001 \f
1002 /*
1003 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1004 %                                                                             %
1005 %                                                                             %
1006 %                                                                             %
1007 %   C o p y I m a g e P i x e l s                                             %
1008 %                                                                             %
1009 %                                                                             %
1010 %                                                                             %
1011 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1012 %
1013 %  CopyImagePixels() copies pixels from the source image as defined by the
1014 %  geometry the destination image at the specified offset.
1015 %
1016 %  The format of the CopyImagePixels method is:
1017 %
1018 %      MagickBooleanType CopyImagePixels(Image *image,const Image *source_image,
1019 %        const RectangleInfo *geometry,const OffsetInfo *offset,
1020 %        ExceptionInfo *exception);
1021 %
1022 %  A description of each parameter follows:
1023 %
1024 %    o image: the destination image.
1025 %
1026 %    o source_image: the source image.
1027 %
1028 %    o geometry: define the dimensions of the source pixel rectangle.
1029 %
1030 %    o offset: define the offset in the destination image.
1031 %
1032 %    o exception: return any errors or warnings in this structure.
1033 %
1034 */
1035 MagickExport MagickBooleanType CopyImagePixels(Image *image,
1036   const Image *source_image,const RectangleInfo *geometry,
1037   const OffsetInfo *offset,ExceptionInfo *exception)
1038 {
1039 #define CopyImageTag  "Copy/Image"
1040
1041   CacheView
1042     *image_view,
1043     *source_view;
1044
1045   MagickBooleanType
1046     status;
1047
1048   MagickOffsetType
1049     progress;
1050
1051   ssize_t
1052     y;
1053
1054   assert(image != (Image *) NULL);
1055   if (image->debug != MagickFalse)
1056     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1057   assert(source_image != (Image *) NULL);
1058   assert(geometry != (RectangleInfo *) NULL);
1059   assert(offset != (OffsetInfo *) NULL);
1060   if ((offset->x < 0) || (offset->y < 0) ||
1061       ((ssize_t) (offset->x+geometry->width) > (ssize_t) image->columns) ||
1062       ((ssize_t) (offset->y+geometry->height) > (ssize_t) image->rows))
1063     ThrowBinaryException(OptionError,"GeometryDoesNotContainImage",
1064       image->filename);
1065   if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
1066     return(MagickFalse);
1067   /*
1068     Copy image pixels.
1069   */
1070   status=MagickTrue;
1071   progress=0;
1072   source_view=AcquireVirtualCacheView(source_image,exception);
1073   image_view=AcquireAuthenticCacheView(image,exception);
1074 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1075   #pragma omp parallel for schedule(static,4) shared(progress,status) \
1076     magick_threads(image,source_image,geometry->height,1)
1077 #endif
1078   for (y=0; y < (ssize_t) geometry->height; y++)
1079   {
1080     MagickBooleanType
1081       sync;
1082
1083     register const Quantum
1084       *magick_restrict p;
1085
1086     register ssize_t
1087       x;
1088
1089     register Quantum
1090       *magick_restrict q;
1091
1092     if (status == MagickFalse)
1093       continue;
1094     p=GetCacheViewVirtualPixels(source_view,geometry->x,y+geometry->y,
1095       geometry->width,1,exception);
1096     q=QueueCacheViewAuthenticPixels(image_view,offset->x,y+offset->y,
1097       geometry->width,1,exception);
1098     if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
1099       {
1100         status=MagickFalse;
1101         continue;
1102       }
1103     for (x=0; x < (ssize_t) geometry->width; x++)
1104     {
1105       register ssize_t
1106         i;
1107
1108       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1109       { 
1110         PixelChannel channel=GetPixelChannelChannel(image,i);
1111         PixelTrait traits=GetPixelChannelTraits(image,channel);
1112         PixelTrait source_traits=GetPixelChannelTraits(source_image,channel);
1113         if ((traits == UndefinedPixelTrait) ||
1114             (source_traits == UndefinedPixelTrait))
1115           continue;
1116         SetPixelChannel(image,channel,p[i],q);
1117       }
1118       p+=GetPixelChannels(source_image);
1119       q+=GetPixelChannels(image);
1120     }
1121     sync=SyncCacheViewAuthenticPixels(image_view,exception);
1122     if (sync == MagickFalse)
1123       status=MagickFalse;
1124     if (image->progress_monitor != (MagickProgressMonitor) NULL)
1125       {
1126         MagickBooleanType
1127           proceed;
1128
1129 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1130         #pragma omp critical (MagickCore_CopyImage)
1131 #endif
1132         proceed=SetImageProgress(image,CopyImageTag,progress++,image->rows);
1133         if (proceed == MagickFalse)
1134           status=MagickFalse;
1135       }
1136   }
1137   source_view=DestroyCacheView(source_view);
1138   image_view=DestroyCacheView(image_view);
1139   return(status);
1140 }
1141 \f
1142 /*
1143 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1144 %                                                                             %
1145 %                                                                             %
1146 %                                                                             %
1147 %   D e s t r o y I m a g e                                                   %
1148 %                                                                             %
1149 %                                                                             %
1150 %                                                                             %
1151 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1152 %
1153 %  DestroyImage() dereferences an image, deallocating memory associated with
1154 %  the image if the reference count becomes zero.
1155 %
1156 %  The format of the DestroyImage method is:
1157 %
1158 %      Image *DestroyImage(Image *image)
1159 %
1160 %  A description of each parameter follows:
1161 %
1162 %    o image: the image.
1163 %
1164 */
1165 MagickExport Image *DestroyImage(Image *image)
1166 {
1167   MagickBooleanType
1168     destroy;
1169
1170   /*
1171     Dereference image.
1172   */
1173   assert(image != (Image *) NULL);
1174   assert(image->signature == MagickCoreSignature);
1175   if (image->debug != MagickFalse)
1176     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1177   destroy=MagickFalse;
1178   LockSemaphoreInfo(image->semaphore);
1179   image->reference_count--;
1180   if (image->reference_count == 0)
1181     destroy=MagickTrue;
1182   UnlockSemaphoreInfo(image->semaphore);
1183   if (destroy == MagickFalse)
1184     return((Image *) NULL);
1185   /*
1186     Destroy image.
1187   */
1188   DestroyImagePixels(image);
1189   image->channel_map=DestroyPixelChannelMap(image->channel_map);
1190   if (image->montage != (char *) NULL)
1191     image->montage=DestroyString(image->montage);
1192   if (image->directory != (char *) NULL)
1193     image->directory=DestroyString(image->directory);
1194   if (image->colormap != (PixelInfo *) NULL)
1195     image->colormap=(PixelInfo *) RelinquishMagickMemory(image->colormap);
1196   if (image->geometry != (char *) NULL)
1197     image->geometry=DestroyString(image->geometry);
1198   DestroyImageProfiles(image);
1199   DestroyImageProperties(image);
1200   DestroyImageArtifacts(image);
1201   if (image->ascii85 != (Ascii85Info *) NULL)
1202     image->ascii85=(Ascii85Info *) RelinquishMagickMemory(image->ascii85);
1203   if (image->image_info != (ImageInfo *) NULL)
1204     image->image_info=DestroyImageInfo(image->image_info);
1205   DestroyBlob(image);
1206   if (image->semaphore != (SemaphoreInfo *) NULL)
1207     RelinquishSemaphoreInfo(&image->semaphore);
1208   image->signature=(~MagickCoreSignature);
1209   image=(Image *) RelinquishMagickMemory(image);
1210   return(image);
1211 }
1212 \f
1213 /*
1214 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1215 %                                                                             %
1216 %                                                                             %
1217 %                                                                             %
1218 %   D e s t r o y I m a g e I n f o                                           %
1219 %                                                                             %
1220 %                                                                             %
1221 %                                                                             %
1222 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1223 %
1224 %  DestroyImageInfo() deallocates memory associated with an ImageInfo
1225 %  structure.
1226 %
1227 %  The format of the DestroyImageInfo method is:
1228 %
1229 %      ImageInfo *DestroyImageInfo(ImageInfo *image_info)
1230 %
1231 %  A description of each parameter follows:
1232 %
1233 %    o image_info: the image info.
1234 %
1235 */
1236 MagickExport ImageInfo *DestroyImageInfo(ImageInfo *image_info)
1237 {
1238   assert(image_info != (ImageInfo *) NULL);
1239   assert(image_info->signature == MagickCoreSignature);
1240   if (image_info->debug != MagickFalse)
1241     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1242       image_info->filename);
1243   if (image_info->size != (char *) NULL)
1244     image_info->size=DestroyString(image_info->size);
1245   if (image_info->extract != (char *) NULL)
1246     image_info->extract=DestroyString(image_info->extract);
1247   if (image_info->scenes != (char *) NULL)
1248     image_info->scenes=DestroyString(image_info->scenes);
1249   if (image_info->page != (char *) NULL)
1250     image_info->page=DestroyString(image_info->page);
1251   if (image_info->sampling_factor != (char *) NULL)
1252     image_info->sampling_factor=DestroyString(
1253       image_info->sampling_factor);
1254   if (image_info->server_name != (char *) NULL)
1255     image_info->server_name=DestroyString(
1256       image_info->server_name);
1257   if (image_info->font != (char *) NULL)
1258     image_info->font=DestroyString(image_info->font);
1259   if (image_info->texture != (char *) NULL)
1260     image_info->texture=DestroyString(image_info->texture);
1261   if (image_info->density != (char *) NULL)
1262     image_info->density=DestroyString(image_info->density);
1263   if (image_info->cache != (void *) NULL)
1264     image_info->cache=DestroyPixelCache(image_info->cache);
1265   if (image_info->profile != (StringInfo *) NULL)
1266     image_info->profile=(void *) DestroyStringInfo((StringInfo *)
1267       image_info->profile);
1268   DestroyImageOptions(image_info);
1269   image_info->signature=(~MagickCoreSignature);
1270   image_info=(ImageInfo *) RelinquishMagickMemory(image_info);
1271   return(image_info);
1272 }
1273 \f
1274 /*
1275 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1276 %                                                                             %
1277 %                                                                             %
1278 %                                                                             %
1279 +   D i s a s s o c i a t e I m a g e S t r e a m                             %
1280 %                                                                             %
1281 %                                                                             %
1282 %                                                                             %
1283 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1284 %
1285 %  DisassociateImageStream() disassociates the image stream.  It checks if the
1286 %  blob of the specified image is referenced by other images. If the reference
1287 %  count is higher then 1 a new blob is assigned to the specified image.
1288 %
1289 %  The format of the DisassociateImageStream method is:
1290 %
1291 %      void DisassociateImageStream(const Image *image)
1292 %
1293 %  A description of each parameter follows:
1294 %
1295 %    o image: the image.
1296 %
1297 */
1298 MagickExport void DisassociateImageStream(Image *image)
1299 {
1300   assert(image != (Image *) NULL);
1301   assert(image->signature == MagickCoreSignature);
1302   if (image->debug != MagickFalse)
1303     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1304   DisassociateBlob(image);
1305 }
1306 \f
1307 /*
1308 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1309 %                                                                             %
1310 %                                                                             %
1311 %                                                                             %
1312 %   G e t I m a g e I n f o                                                   %
1313 %                                                                             %
1314 %                                                                             %
1315 %                                                                             %
1316 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1317 %
1318 %  GetImageInfo() initializes image_info to default values.
1319 %
1320 %  The format of the GetImageInfo method is:
1321 %
1322 %      void GetImageInfo(ImageInfo *image_info)
1323 %
1324 %  A description of each parameter follows:
1325 %
1326 %    o image_info: the image info.
1327 %
1328 */
1329 MagickExport void GetImageInfo(ImageInfo *image_info)
1330 {
1331   char
1332     *synchronize;
1333
1334   ExceptionInfo
1335     *exception;
1336
1337   /*
1338     File and image dimension members.
1339   */
1340   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1341   assert(image_info != (ImageInfo *) NULL);
1342   (void) ResetMagickMemory(image_info,0,sizeof(*image_info));
1343   image_info->adjoin=MagickTrue;
1344   image_info->interlace=NoInterlace;
1345   image_info->channel=DefaultChannels;
1346   image_info->quality=UndefinedCompressionQuality;
1347   image_info->antialias=MagickTrue;
1348   image_info->dither=MagickTrue;
1349   synchronize=GetEnvironmentValue("MAGICK_SYNCHRONIZE");
1350   if (synchronize != (const char *) NULL)
1351     {
1352       image_info->synchronize=IsStringTrue(synchronize);
1353       synchronize=DestroyString(synchronize);
1354     }
1355   exception=AcquireExceptionInfo();
1356   (void) QueryColorCompliance(AlphaColor,AllCompliance,&image_info->alpha_color,
1357     exception);
1358   (void) QueryColorCompliance(BackgroundColor,AllCompliance,
1359     &image_info->background_color,exception);
1360   (void) QueryColorCompliance(BorderColor,AllCompliance,
1361     &image_info->border_color,exception);
1362   (void) QueryColorCompliance(TransparentColor,AllCompliance,
1363     &image_info->transparent_color,exception);
1364   exception=DestroyExceptionInfo(exception);
1365   image_info->debug=IsEventLogging();
1366   image_info->signature=MagickCoreSignature;
1367 }
1368 \f
1369 /*
1370 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1371 %                                                                             %
1372 %                                                                             %
1373 %                                                                             %
1374 %   G e t I m a g e I n f o F i l e                                           %
1375 %                                                                             %
1376 %                                                                             %
1377 %                                                                             %
1378 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1379 %
1380 %  GetImageInfoFile() returns the image info file member.
1381 %
1382 %  The format of the GetImageInfoFile method is:
1383 %
1384 %      FILE *GetImageInfoFile(const ImageInfo *image_info)
1385 %
1386 %  A description of each parameter follows:
1387 %
1388 %    o image_info: the image info.
1389 %
1390 */
1391 MagickExport FILE *GetImageInfoFile(const ImageInfo *image_info)
1392 {
1393   return(image_info->file);
1394 }
1395 \f
1396 /*
1397 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1398 %                                                                             %
1399 %                                                                             %
1400 %                                                                             %
1401 %   G e t I m a g e M a s k                                                   %
1402 %                                                                             %
1403 %                                                                             %
1404 %                                                                             %
1405 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1406 %
1407 %  GetImageMask() returns the mask associated with the image.
1408 %
1409 %  The format of the GetImageMask method is:
1410 %
1411 %      Image *GetImageMask(const Image *image,const PixelMask type,
1412 %        ExceptionInfo *exception)
1413 %
1414 %  A description of each parameter follows:
1415 %
1416 %    o image: the image.
1417 %
1418 %    o type: the mask type, ReadPixelMask or WritePixelMask.
1419 %
1420 */
1421 MagickExport Image *GetImageMask(const Image *image,const PixelMask type,
1422   ExceptionInfo *exception)
1423 {
1424   CacheView
1425     *mask_view,
1426     *image_view;
1427
1428   Image
1429     *mask_image;
1430
1431   MagickBooleanType
1432     status;
1433
1434   ssize_t
1435     y;
1436
1437   /*
1438     Get image mask.
1439   */
1440   assert(image != (Image *) NULL);
1441   if (image->debug != MagickFalse)
1442     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1443   assert(image->signature == MagickCoreSignature);
1444   mask_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
1445   if (mask_image == (Image *) NULL)
1446     return((Image *) NULL);
1447   status=MagickTrue;
1448   mask_image->alpha_trait=UndefinedPixelTrait;
1449   (void) SetImageColorspace(mask_image,GRAYColorspace,exception);
1450   mask_image->read_mask=MagickFalse;
1451   image_view=AcquireVirtualCacheView(image,exception);
1452   mask_view=AcquireAuthenticCacheView(mask_image,exception);
1453   for (y=0; y < (ssize_t) image->rows; y++)
1454   {
1455     register const Quantum
1456       *magick_restrict p;
1457
1458     register Quantum
1459       *magick_restrict q;
1460
1461     register ssize_t
1462       x;
1463
1464     if (status == MagickFalse)
1465       continue;
1466     p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1467     q=GetCacheViewAuthenticPixels(mask_view,0,y,mask_image->columns,1,
1468       exception);
1469     if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
1470       {
1471         status=MagickFalse;
1472         continue;
1473       }
1474     for (x=0; x < (ssize_t) image->columns; x++)
1475     {
1476       switch (type)
1477       {
1478         case WritePixelMask:
1479         {
1480           SetPixelGray(mask_image,GetPixelWriteMask(image,p),q);
1481           break;
1482         }
1483         default:
1484         {
1485           SetPixelGray(mask_image,GetPixelReadMask(image,p),q);
1486           break;
1487         }
1488       }
1489       p+=GetPixelChannels(image);
1490       q+=GetPixelChannels(mask_image);
1491     }
1492     if (SyncCacheViewAuthenticPixels(mask_view,exception) == MagickFalse)
1493       status=MagickFalse;
1494   }
1495   mask_view=DestroyCacheView(mask_view);
1496   image_view=DestroyCacheView(image_view);
1497   if (status == MagickFalse)
1498     mask_image=DestroyImage(mask_image);
1499   return(mask_image);
1500 }
1501 \f
1502 /*
1503 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1504 %                                                                             %
1505 %                                                                             %
1506 %                                                                             %
1507 +   G e t I m a g e R e f e r e n c e C o u n t                               %
1508 %                                                                             %
1509 %                                                                             %
1510 %                                                                             %
1511 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1512 %
1513 %  GetImageReferenceCount() returns the image reference count.
1514 %
1515 %  The format of the GetReferenceCount method is:
1516 %
1517 %      ssize_t GetImageReferenceCount(Image *image)
1518 %
1519 %  A description of each parameter follows:
1520 %
1521 %    o image: the image.
1522 %
1523 */
1524 MagickExport ssize_t GetImageReferenceCount(Image *image)
1525 {
1526   ssize_t
1527     reference_count;
1528
1529   assert(image != (Image *) NULL);
1530   assert(image->signature == MagickCoreSignature);
1531   if (image->debug != MagickFalse)
1532     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1533   LockSemaphoreInfo(image->semaphore);
1534   reference_count=image->reference_count;
1535   UnlockSemaphoreInfo(image->semaphore);
1536   return(reference_count);
1537 }
1538 \f
1539 /*
1540 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1541 %                                                                             %
1542 %                                                                             %
1543 %                                                                             %
1544 %   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                       %
1545 %                                                                             %
1546 %                                                                             %
1547 %                                                                             %
1548 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1549 %
1550 %  GetImageVirtualPixelMethod() gets the "virtual pixels" method for the
1551 %  image.  A virtual pixel is any pixel access that is outside the boundaries
1552 %  of the image cache.
1553 %
1554 %  The format of the GetImageVirtualPixelMethod() method is:
1555 %
1556 %      VirtualPixelMethod GetImageVirtualPixelMethod(const Image *image)
1557 %
1558 %  A description of each parameter follows:
1559 %
1560 %    o image: the image.
1561 %
1562 */
1563 MagickExport VirtualPixelMethod GetImageVirtualPixelMethod(const Image *image)
1564 {
1565   assert(image != (Image *) NULL);
1566   assert(image->signature == MagickCoreSignature);
1567   if (image->debug != MagickFalse)
1568     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1569   return(GetPixelCacheVirtualMethod(image));
1570 }
1571 \f
1572 /*
1573 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1574 %                                                                             %
1575 %                                                                             %
1576 %                                                                             %
1577 %  I n t e r p r e t I m a g e F i l e n a m e                                %
1578 %                                                                             %
1579 %                                                                             %
1580 %                                                                             %
1581 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1582 %
1583 %  InterpretImageFilename() interprets embedded characters in an image filename.
1584 %  The filename length is returned.
1585 %
1586 %  The format of the InterpretImageFilename method is:
1587 %
1588 %      size_t InterpretImageFilename(const ImageInfo *image_info,Image *image,
1589 %        const char *format,int value,char *filename,ExceptionInfo *exception)
1590 %
1591 %  A description of each parameter follows.
1592 %
1593 %    o image_info: the image info..
1594 %
1595 %    o image: the image.
1596 %
1597 %    o format:  A filename describing the format to use to write the numeric
1598 %      argument. Only the first numeric format identifier is replaced.
1599 %
1600 %    o value:  Numeric value to substitute into format filename.
1601 %
1602 %    o filename:  return the formatted filename in this character buffer.
1603 %
1604 %    o exception: return any errors or warnings in this structure.
1605 %
1606 */
1607 MagickExport size_t InterpretImageFilename(const ImageInfo *image_info,
1608   Image *image,const char *format,int value,char *filename,
1609   ExceptionInfo *exception)
1610 {
1611   char
1612     *q;
1613
1614   int
1615     c;
1616
1617   MagickBooleanType
1618     canonical;
1619
1620   register const char
1621     *p;
1622
1623   size_t
1624     length;
1625
1626   canonical=MagickFalse;
1627   length=0;
1628   (void) CopyMagickString(filename,format,MagickPathExtent);
1629   for (p=strchr(format,'%'); p != (char *) NULL; p=strchr(p+1,'%'))
1630   {
1631     q=(char *) p+1;
1632     if (*q == '%')
1633       {
1634         p=q+1;
1635         continue;
1636       }
1637     if (*q == '0')
1638       {
1639         ssize_t
1640           foo;
1641
1642         foo=(ssize_t) strtol(q,&q,10);
1643         (void) foo;
1644       }
1645     switch (*q)
1646     {
1647       case 'd':
1648       case 'o':
1649       case 'x':
1650       {
1651         q++;
1652         c=(*q);
1653         *q='\0';
1654         (void) FormatLocaleString(filename+(p-format),(size_t)
1655           (MagickPathExtent-(p-format)),p,value);
1656         *q=c;
1657         (void) ConcatenateMagickString(filename,q,MagickPathExtent);
1658         canonical=MagickTrue;
1659         if (*(q-1) != '%')
1660           break;
1661         p++;
1662         break;
1663       }
1664       case '[':
1665       {
1666         char
1667           pattern[MagickPathExtent];
1668
1669         const char
1670           *option;
1671
1672         register char
1673           *r;
1674
1675         register ssize_t
1676           i;
1677
1678         ssize_t
1679           depth;
1680
1681         /*
1682           Image option.
1683         */
1684         /* FUTURE: Compare update with code from InterpretImageProperties()
1685            Note that a 'filename:' property should not need depth recursion.
1686         */
1687         if (strchr(p,']') == (char *) NULL)
1688           break;
1689         depth=1;
1690         r=q+1;
1691         for (i=0; (i < (MagickPathExtent-1L)) && (*r != '\0'); i++)
1692         {
1693           if (*r == '[')
1694             depth++;
1695           if (*r == ']')
1696             depth--;
1697           if (depth <= 0)
1698             break;
1699           pattern[i]=(*r++);
1700         }
1701         pattern[i]='\0';
1702         if (LocaleNCompare(pattern,"filename:",9) != 0)
1703           break;
1704         option=(const char *) NULL;
1705         if (image != (Image *) NULL)
1706           option=GetImageProperty(image,pattern,exception);
1707         if ((option == (const char *) NULL) && (image != (Image *) NULL))
1708           option=GetImageArtifact(image,pattern);
1709         if ((option == (const char *) NULL) &&
1710             (image_info != (ImageInfo *) NULL))
1711           option=GetImageOption(image_info,pattern);
1712         if (option == (const char *) NULL)
1713           break;
1714         q--;
1715         c=(*q);
1716         *q='\0';
1717         (void) CopyMagickString(filename+(p-format-length),option,(size_t)
1718           (MagickPathExtent-(p-format-length)));
1719         length+=strlen(pattern)-1;
1720         *q=c;
1721         (void) ConcatenateMagickString(filename,r+1,MagickPathExtent);
1722         canonical=MagickTrue;
1723         if (*(q-1) != '%')
1724           break;
1725         p++;
1726         break;
1727       }
1728       default:
1729         break;
1730     }
1731   }
1732   for (q=filename; *q != '\0'; q++)
1733     if ((*q == '%') && (*(q+1) == '%'))
1734       {
1735         (void) CopyMagickString(q,q+1,(size_t) (MagickPathExtent-(q-filename)));
1736         canonical=MagickTrue;
1737       }
1738   if (canonical == MagickFalse)
1739     (void) CopyMagickString(filename,format,MagickPathExtent);
1740   return(strlen(filename));
1741 }
1742 \f
1743 /*
1744 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1745 %                                                                             %
1746 %                                                                             %
1747 %                                                                             %
1748 %   I s H i g h D y n a m i c R a n g e I m a g e                             %
1749 %                                                                             %
1750 %                                                                             %
1751 %                                                                             %
1752 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1753 %
1754 %  IsHighDynamicRangeImage() returns MagickTrue if any pixel component is
1755 %  non-integer or exceeds the bounds of the quantum depth (e.g. for Q16
1756 %  0..65535.
1757 %
1758 %  The format of the IsHighDynamicRangeImage method is:
1759 %
1760 %      MagickBooleanType IsHighDynamicRangeImage(const Image *image,
1761 %        ExceptionInfo *exception)
1762 %
1763 %  A description of each parameter follows:
1764 %
1765 %    o image: the image.
1766 %
1767 %    o exception: return any errors or warnings in this structure.
1768 %
1769 */
1770 MagickExport MagickBooleanType IsHighDynamicRangeImage(const Image *image,
1771   ExceptionInfo *exception)
1772 {
1773 #if !defined(MAGICKCORE_HDRI_SUPPORT)
1774   (void) image;
1775   (void) exception;
1776   return(MagickFalse);
1777 #else
1778   CacheView
1779     *image_view;
1780
1781   MagickBooleanType
1782     status;
1783
1784   ssize_t
1785     y;
1786
1787   assert(image != (Image *) NULL);
1788   assert(image->signature == MagickCoreSignature);
1789   if (image->debug != MagickFalse)
1790     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1791   status=MagickTrue;
1792   image_view=AcquireVirtualCacheView(image,exception);
1793 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1794   #pragma omp parallel for schedule(static,4) shared(status) \
1795     magick_threads(image,image,image->rows,1)
1796 #endif
1797   for (y=0; y < (ssize_t) image->rows; y++)
1798   {
1799     register const Quantum
1800       *p;
1801
1802     register ssize_t
1803       x;
1804
1805     if (status == MagickFalse)
1806       continue;
1807     p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1808     if (p == (const Quantum *) NULL)
1809       {
1810         status=MagickFalse;
1811         continue;
1812       }
1813     for (x=0; x < (ssize_t) image->columns; x++)
1814     {
1815       register ssize_t
1816         i;
1817
1818       if (GetPixelReadMask(image,p) == 0)
1819         {
1820           p+=GetPixelChannels(image);
1821           continue;
1822         }
1823       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1824       {
1825         double
1826           pixel;
1827
1828         PixelTrait
1829           traits;
1830
1831         traits=GetPixelChannelTraits(image,(PixelChannel) i);
1832         if (traits == UndefinedPixelTrait)
1833           continue;
1834         pixel=(double) p[i];
1835         if ((pixel < 0.0) || (pixel > QuantumRange) ||
1836             (pixel != (double) ((QuantumAny) pixel)))
1837           break;
1838       }
1839       p+=GetPixelChannels(image);
1840       if (i < (ssize_t) GetPixelChannels(image))
1841         status=MagickFalse;
1842     }
1843     if (x < (ssize_t) image->columns)
1844       status=MagickFalse;
1845   }
1846   image_view=DestroyCacheView(image_view);
1847   return(status != MagickFalse ? MagickFalse : MagickTrue);
1848 #endif
1849 }
1850 \f
1851 /*
1852 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1853 %                                                                             %
1854 %                                                                             %
1855 %                                                                             %
1856 %     I s I m a g e O b j e c t                                               %
1857 %                                                                             %
1858 %                                                                             %
1859 %                                                                             %
1860 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1861 %
1862 %  IsImageObject() returns MagickTrue if the image sequence contains a valid
1863 %  set of image objects.
1864 %
1865 %  The format of the IsImageObject method is:
1866 %
1867 %      MagickBooleanType IsImageObject(const Image *image)
1868 %
1869 %  A description of each parameter follows:
1870 %
1871 %    o image: the image.
1872 %
1873 */
1874 MagickExport MagickBooleanType IsImageObject(const Image *image)
1875 {
1876   register const Image
1877     *p;
1878
1879   assert(image != (Image *) NULL);
1880   if (image->debug != MagickFalse)
1881     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1882   for (p=image; p != (Image *) NULL; p=GetNextImageInList(p))
1883     if (p->signature != MagickCoreSignature)
1884       return(MagickFalse);
1885   return(MagickTrue);
1886 }
1887 \f
1888 /*
1889 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1890 %                                                                             %
1891 %                                                                             %
1892 %                                                                             %
1893 %     I s T a i n t I m a g e                                                 %
1894 %                                                                             %
1895 %                                                                             %
1896 %                                                                             %
1897 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1898 %
1899 %  IsTaintImage() returns MagickTrue any pixel in the image has been altered
1900 %  since it was first constituted.
1901 %
1902 %  The format of the IsTaintImage method is:
1903 %
1904 %      MagickBooleanType IsTaintImage(const Image *image)
1905 %
1906 %  A description of each parameter follows:
1907 %
1908 %    o image: the image.
1909 %
1910 */
1911 MagickExport MagickBooleanType IsTaintImage(const Image *image)
1912 {
1913   char
1914     magick[MagickPathExtent],
1915     filename[MagickPathExtent];
1916
1917   register const Image
1918     *p;
1919
1920   assert(image != (Image *) NULL);
1921   if (image->debug != MagickFalse)
1922     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1923   assert(image->signature == MagickCoreSignature);
1924   (void) CopyMagickString(magick,image->magick,MagickPathExtent);
1925   (void) CopyMagickString(filename,image->filename,MagickPathExtent);
1926   for (p=image; p != (Image *) NULL; p=GetNextImageInList(p))
1927   {
1928     if (p->taint != MagickFalse)
1929       return(MagickTrue);
1930     if (LocaleCompare(p->magick,magick) != 0)
1931       return(MagickTrue);
1932     if (LocaleCompare(p->filename,filename) != 0)
1933       return(MagickTrue);
1934   }
1935   return(MagickFalse);
1936 }
1937 \f
1938 /*
1939 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1940 %                                                                             %
1941 %                                                                             %
1942 %                                                                             %
1943 %   M o d i f y I m a g e                                                     %
1944 %                                                                             %
1945 %                                                                             %
1946 %                                                                             %
1947 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1948 %
1949 %  ModifyImage() ensures that there is only a single reference to the image
1950 %  to be modified, updating the provided image pointer to point to a clone of
1951 %  the original image if necessary.
1952 %
1953 %  The format of the ModifyImage method is:
1954 %
1955 %      MagickBooleanType ModifyImage(Image *image,ExceptionInfo *exception)
1956 %
1957 %  A description of each parameter follows:
1958 %
1959 %    o image: the image.
1960 %
1961 %    o exception: return any errors or warnings in this structure.
1962 %
1963 */
1964 MagickExport MagickBooleanType ModifyImage(Image **image,
1965   ExceptionInfo *exception)
1966 {
1967   Image
1968     *clone_image;
1969
1970   assert(image != (Image **) NULL);
1971   assert(*image != (Image *) NULL);
1972   assert((*image)->signature == MagickCoreSignature);
1973   if ((*image)->debug != MagickFalse)
1974     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",(*image)->filename);
1975   if (GetImageReferenceCount(*image) <= 1)
1976     return(MagickTrue);
1977   clone_image=CloneImage(*image,0,0,MagickTrue,exception);
1978   LockSemaphoreInfo((*image)->semaphore);
1979   (*image)->reference_count--;
1980   UnlockSemaphoreInfo((*image)->semaphore);
1981   *image=clone_image;
1982   return(MagickTrue);
1983 }
1984 \f
1985 /*
1986 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1987 %                                                                             %
1988 %                                                                             %
1989 %                                                                             %
1990 %   N e w M a g i c k I m a g e                                               %
1991 %                                                                             %
1992 %                                                                             %
1993 %                                                                             %
1994 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1995 %
1996 %  NewMagickImage() creates a blank image canvas of the specified size and
1997 %  background color.
1998 %
1999 %  The format of the NewMagickImage method is:
2000 %
2001 %      Image *NewMagickImage(const ImageInfo *image_info,const size_t width,
2002 %        const size_t height,const PixelInfo *background,
2003 %        ExceptionInfo *exception)
2004 %
2005 %  A description of each parameter follows:
2006 %
2007 %    o image: the image.
2008 %
2009 %    o width: the image width.
2010 %
2011 %    o height: the image height.
2012 %
2013 %    o background: the image color.
2014 %
2015 %    o exception: return any errors or warnings in this structure.
2016 %
2017 */
2018 MagickExport Image *NewMagickImage(const ImageInfo *image_info,
2019   const size_t width,const size_t height,const PixelInfo *background,
2020   ExceptionInfo *exception)
2021 {
2022   CacheView
2023     *image_view;
2024
2025   Image
2026     *image;
2027
2028   MagickBooleanType
2029     status;
2030
2031   ssize_t
2032     y;
2033
2034   assert(image_info != (const ImageInfo *) NULL);
2035   if (image_info->debug != MagickFalse)
2036     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2037   assert(image_info->signature == MagickCoreSignature);
2038   assert(background != (const PixelInfo *) NULL);
2039   image=AcquireImage(image_info,exception);
2040   image->columns=width;
2041   image->rows=height;
2042   image->colorspace=background->colorspace;
2043   image->alpha_trait=background->alpha_trait;
2044   image->fuzz=background->fuzz;
2045   image->depth=background->depth;
2046   status=MagickTrue;
2047   image_view=AcquireAuthenticCacheView(image,exception);
2048 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2049   #pragma omp parallel for schedule(static,4) shared(status) \
2050     magick_threads(image,image,image->rows,1)
2051 #endif
2052   for (y=0; y < (ssize_t) image->rows; y++)
2053   {
2054     register Quantum
2055       *magick_restrict q;
2056
2057     register ssize_t
2058       x;
2059
2060     if (status == MagickFalse)
2061       continue;
2062     q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2063     if (q == (Quantum *) NULL)
2064       {
2065         status=MagickFalse;
2066         continue;
2067       }
2068     for (x=0; x < (ssize_t) image->columns; x++)
2069     {
2070       SetPixelViaPixelInfo(image,background,q);
2071       q+=GetPixelChannels(image);
2072     }
2073     if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2074       status=MagickFalse;
2075   }
2076   image_view=DestroyCacheView(image_view);
2077   if (status == MagickFalse)
2078     image=DestroyImage(image);
2079   return(image);
2080 }
2081 \f
2082 /*
2083 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2084 %                                                                             %
2085 %                                                                             %
2086 %                                                                             %
2087 %   R e f e r e n c e I m a g e                                               %
2088 %                                                                             %
2089 %                                                                             %
2090 %                                                                             %
2091 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2092 %
2093 %  ReferenceImage() increments the reference count associated with an image
2094 %  returning a pointer to the image.
2095 %
2096 %  The format of the ReferenceImage method is:
2097 %
2098 %      Image *ReferenceImage(Image *image)
2099 %
2100 %  A description of each parameter follows:
2101 %
2102 %    o image: the image.
2103 %
2104 */
2105 MagickExport Image *ReferenceImage(Image *image)
2106 {
2107   assert(image != (Image *) NULL);
2108   if (image->debug != MagickFalse)
2109     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2110   assert(image->signature == MagickCoreSignature);
2111   LockSemaphoreInfo(image->semaphore);
2112   image->reference_count++;
2113   UnlockSemaphoreInfo(image->semaphore);
2114   return(image);
2115 }
2116 \f
2117 /*
2118 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2119 %                                                                             %
2120 %                                                                             %
2121 %                                                                             %
2122 %   R e s e t I m a g e P a g e                                               %
2123 %                                                                             %
2124 %                                                                             %
2125 %                                                                             %
2126 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2127 %
2128 %  ResetImagePage() resets the image page canvas and position.
2129 %
2130 %  The format of the ResetImagePage method is:
2131 %
2132 %      MagickBooleanType ResetImagePage(Image *image,const char *page)
2133 %
2134 %  A description of each parameter follows:
2135 %
2136 %    o image: the image.
2137 %
2138 %    o page: the relative page specification.
2139 %
2140 */
2141 MagickExport MagickBooleanType ResetImagePage(Image *image,const char *page)
2142 {
2143   MagickStatusType
2144     flags;
2145
2146   RectangleInfo
2147     geometry;
2148
2149   assert(image != (Image *) NULL);
2150   assert(image->signature == MagickCoreSignature);
2151   if (image->debug != MagickFalse)
2152     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2153   flags=ParseAbsoluteGeometry(page,&geometry);
2154   if ((flags & WidthValue) != 0)
2155     {
2156       if ((flags & HeightValue) == 0)
2157         geometry.height=geometry.width;
2158       image->page.width=geometry.width;
2159       image->page.height=geometry.height;
2160     }
2161   if ((flags & AspectValue) != 0)
2162     {
2163       if ((flags & XValue) != 0)
2164         image->page.x+=geometry.x;
2165       if ((flags & YValue) != 0)
2166         image->page.y+=geometry.y;
2167     }
2168   else
2169     {
2170       if ((flags & XValue) != 0)
2171         {
2172           image->page.x=geometry.x;
2173           if ((image->page.width == 0) && (geometry.x > 0))
2174             image->page.width=image->columns+geometry.x;
2175         }
2176       if ((flags & YValue) != 0)
2177         {
2178           image->page.y=geometry.y;
2179           if ((image->page.height == 0) && (geometry.y > 0))
2180             image->page.height=image->rows+geometry.y;
2181         }
2182     }
2183   return(MagickTrue);
2184 }
2185 \f
2186 /*
2187 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2188 %                                                                             %
2189 %                                                                             %
2190 %                                                                             %
2191 %   S e t I m a g e B a c k g r o u n d C o l o r                             %
2192 %                                                                             %
2193 %                                                                             %
2194 %                                                                             %
2195 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2196 %
2197 %  SetImageBackgroundColor() initializes the image pixels to the image
2198 %  background color.  The background color is defined by the background_color
2199 %  member of the image structure.
2200 %
2201 %  The format of the SetImage method is:
2202 %
2203 %      MagickBooleanType SetImageBackgroundColor(Image *image,
2204 %        ExceptionInfo *exception)
2205 %
2206 %  A description of each parameter follows:
2207 %
2208 %    o image: the image.
2209 %
2210 %    o exception: return any errors or warnings in this structure.
2211 %
2212 */
2213 MagickExport MagickBooleanType SetImageBackgroundColor(Image *image,
2214   ExceptionInfo *exception)
2215 {
2216   CacheView
2217     *image_view;
2218
2219   MagickBooleanType
2220     status;
2221
2222   PixelInfo
2223     background;
2224
2225   ssize_t
2226     y;
2227
2228   assert(image != (Image *) NULL);
2229   if (image->debug != MagickFalse)
2230     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2231   assert(image->signature == MagickCoreSignature);
2232   if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
2233     return(MagickFalse);
2234   ConformPixelInfo(image,&image->background_color,&background,exception);
2235   /*
2236     Set image background color.
2237   */
2238   status=MagickTrue;
2239   image_view=AcquireAuthenticCacheView(image,exception);
2240   for (y=0; y < (ssize_t) image->rows; y++)
2241   {
2242     register Quantum
2243       *magick_restrict q;
2244
2245     register ssize_t
2246       x;
2247
2248     if (status == MagickFalse)
2249       continue;
2250     q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2251     if (q == (Quantum *) NULL)
2252       {
2253         status=MagickFalse;
2254         continue;
2255       }
2256     for (x=0; x < (ssize_t) image->columns; x++)
2257     {
2258       SetPixelViaPixelInfo(image,&background,q);
2259       q+=GetPixelChannels(image);
2260     }
2261     if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2262       status=MagickFalse;
2263   }
2264   image_view=DestroyCacheView(image_view);
2265   return(status);
2266 }
2267 \f
2268 /*
2269 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2270 %                                                                             %
2271 %                                                                             %
2272 %                                                                             %
2273 %   S e t I m a g e C h a n n e l M a s k                                     %
2274 %                                                                             %
2275 %                                                                             %
2276 %                                                                             %
2277 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2278 %
2279 %  SetImageChannelMask() sets the image channel mask from the specified channel
2280 %  mask.
2281 %
2282 %  The format of the SetImageChannelMask method is:
2283 %
2284 %      ChannelType SetImageChannelMask(Image *image,
2285 %        const ChannelType channel_mask)
2286 %
2287 %  A description of each parameter follows:
2288 %
2289 %    o image: the image.
2290 %
2291 %    o channel_mask: the channel mask.
2292 %
2293 */
2294 MagickExport ChannelType SetImageChannelMask(Image *image,
2295   const ChannelType channel_mask)
2296 {
2297   return(SetPixelChannelMask(image,channel_mask));
2298 }
2299 \f
2300 /*
2301 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2302 %                                                                             %
2303 %                                                                             %
2304 %                                                                             %
2305 %   S e t I m a g e C o l o r                                                 %
2306 %                                                                             %
2307 %                                                                             %
2308 %                                                                             %
2309 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2310 %
2311 %  SetImageColor() set the entire image canvas to the specified color.
2312 %
2313 %  The format of the SetImageColor method is:
2314 %
2315 %      MagickBooleanType SetImageColor(Image *image,const PixelInfo *color,
2316 %        ExeptionInfo *exception)
2317 %
2318 %  A description of each parameter follows:
2319 %
2320 %    o image: the image.
2321 %
2322 %    o background: the image color.
2323 %
2324 %    o exception: return any errors or warnings in this structure.
2325 %
2326 */
2327 MagickExport MagickBooleanType SetImageColor(Image *image,
2328   const PixelInfo *color,ExceptionInfo *exception)
2329 {
2330   CacheView
2331     *image_view;
2332
2333   MagickBooleanType
2334     status;
2335
2336   ssize_t
2337     y;
2338
2339   assert(image != (Image *) NULL);
2340   if (image->debug != MagickFalse)
2341     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2342   assert(image->signature == MagickCoreSignature);
2343   assert(color != (const PixelInfo *) NULL);
2344   image->colorspace=color->colorspace;
2345   image->alpha_trait=color->alpha_trait;
2346   image->fuzz=color->fuzz;
2347   image->depth=color->depth;
2348   status=MagickTrue;
2349   image_view=AcquireAuthenticCacheView(image,exception);
2350 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2351   #pragma omp parallel for schedule(static,4) shared(status) \
2352     magick_threads(image,image,image->rows,1)
2353 #endif
2354   for (y=0; y < (ssize_t) image->rows; y++)
2355   {
2356     register Quantum
2357       *magick_restrict q;
2358
2359     register ssize_t
2360       x;
2361
2362     if (status == MagickFalse)
2363       continue;
2364     q=QueueCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2365     if (q == (Quantum *) NULL)
2366       {
2367         status=MagickFalse;
2368         continue;
2369       }
2370     for (x=0; x < (ssize_t) image->columns; x++)
2371     {
2372       SetPixelViaPixelInfo(image,color,q);
2373       q+=GetPixelChannels(image);
2374     }
2375     if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
2376       status=MagickFalse;
2377   }
2378   image_view=DestroyCacheView(image_view);
2379   return(status);
2380 }
2381 \f
2382 /*
2383 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2384 %                                                                             %
2385 %                                                                             %
2386 %                                                                             %
2387 %   S e t I m a g e S t o r a g e C l a s s                                   %
2388 %                                                                             %
2389 %                                                                             %
2390 %                                                                             %
2391 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2392 %
2393 %  SetImageStorageClass() sets the image class: DirectClass for true color
2394 %  images or PseudoClass for colormapped images.
2395 %
2396 %  The format of the SetImageStorageClass method is:
2397 %
2398 %      MagickBooleanType SetImageStorageClass(Image *image,
2399 %        const ClassType storage_class,ExceptionInfo *exception)
2400 %
2401 %  A description of each parameter follows:
2402 %
2403 %    o image: the image.
2404 %
2405 %    o storage_class:  The image class.
2406 %
2407 %    o exception: return any errors or warnings in this structure.
2408 %
2409 */
2410 MagickExport MagickBooleanType SetImageStorageClass(Image *image,
2411   const ClassType storage_class,ExceptionInfo *exception)
2412 {
2413   image->storage_class=storage_class;
2414   return(SyncImagePixelCache(image,exception));
2415 }
2416 \f
2417 /*
2418 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2419 %                                                                             %
2420 %                                                                             %
2421 %                                                                             %
2422 %   S e t I m a g e E x t e n t                                               %
2423 %                                                                             %
2424 %                                                                             %
2425 %                                                                             %
2426 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2427 %
2428 %  SetImageExtent() sets the image size (i.e. columns & rows).
2429 %
2430 %  The format of the SetImageExtent method is:
2431 %
2432 %      MagickBooleanType SetImageExtent(Image *image,const size_t columns,
2433 %        const size_t rows,ExceptionInfo *exception)
2434 %
2435 %  A description of each parameter follows:
2436 %
2437 %    o image: the image.
2438 %
2439 %    o columns:  The image width in pixels.
2440 %
2441 %    o rows:  The image height in pixels.
2442 %
2443 %    o exception: return any errors or warnings in this structure.
2444 %
2445 */
2446 MagickExport MagickBooleanType SetImageExtent(Image *image,const size_t columns,
2447   const size_t rows,ExceptionInfo *exception)
2448 {
2449   if ((columns == 0) || (rows == 0))
2450     return(MagickFalse);
2451   image->columns=columns;
2452   image->rows=rows;
2453   if (image->depth > (8*sizeof(MagickSizeType)))
2454     ThrowBinaryException(ImageError,"ImageDepthNotSupported",image->filename);
2455   return(SyncImagePixelCache(image,exception));
2456 }
2457 \f
2458 /*
2459 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2460 %                                                                             %
2461 %                                                                             %
2462 %                                                                             %
2463 +   S e t I m a g e I n f o                                                   %
2464 %                                                                             %
2465 %                                                                             %
2466 %                                                                             %
2467 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2468 %
2469 %  SetImageInfo() initializes the 'magick' field of the ImageInfo structure.
2470 %  It is set to a type of image format based on the prefix or suffix of the
2471 %  filename.  For example, 'ps:image' returns PS indicating a Postscript image.
2472 %  JPEG is returned for this filename: 'image.jpg'.  The filename prefix has
2473 %  precendence over the suffix.  Use an optional index enclosed in brackets
2474 %  after a file name to specify a desired scene of a multi-resolution image
2475 %  format like Photo CD (e.g. img0001.pcd[4]).  A True (non-zero) return value
2476 %  indicates success.
2477 %
2478 %  The format of the SetImageInfo method is:
2479 %
2480 %      MagickBooleanType SetImageInfo(ImageInfo *image_info,
2481 %        const unsigned int frames,ExceptionInfo *exception)
2482 %
2483 %  A description of each parameter follows:
2484 %
2485 %    o image_info: the image info.
2486 %
2487 %    o frames: the number of images you intend to write.
2488 %
2489 %    o exception: return any errors or warnings in this structure.
2490 %
2491 */
2492 MagickExport MagickBooleanType SetImageInfo(ImageInfo *image_info,
2493   const unsigned int frames,ExceptionInfo *exception)
2494 {
2495   char
2496     component[MagickPathExtent],
2497     magic[MagickPathExtent],
2498     *q;
2499
2500   const MagicInfo
2501     *magic_info;
2502
2503   const MagickInfo
2504     *magick_info;
2505
2506   ExceptionInfo
2507     *sans_exception;
2508
2509   Image
2510     *image;
2511
2512   MagickBooleanType
2513     status;
2514
2515   register const char
2516     *p;
2517
2518   ssize_t
2519     count;
2520
2521   /*
2522     Look for 'image.format' in filename.
2523   */
2524   assert(image_info != (ImageInfo *) NULL);
2525   assert(image_info->signature == MagickCoreSignature);
2526   if (image_info->debug != MagickFalse)
2527     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2528       image_info->filename);
2529   *component='\0';
2530   GetPathComponent(image_info->filename,SubimagePath,component);
2531   if (*component != '\0')
2532     {
2533       /*
2534         Look for scene specification (e.g. img0001.pcd[4]).
2535       */
2536       if (IsSceneGeometry(component,MagickFalse) == MagickFalse)
2537         {
2538           if (IsGeometry(component) != MagickFalse)
2539             (void) CloneString(&image_info->extract,component);
2540         }
2541       else
2542         {
2543           size_t
2544             first,
2545             last;
2546
2547           (void) CloneString(&image_info->scenes,component);
2548           image_info->scene=StringToUnsignedLong(image_info->scenes);
2549           image_info->number_scenes=image_info->scene;
2550           p=image_info->scenes;
2551           for (q=(char *) image_info->scenes; *q != '\0'; p++)
2552           {
2553             while ((isspace((int) ((unsigned char) *p)) != 0) || (*p == ','))
2554               p++;
2555             first=(size_t) strtol(p,&q,10);
2556             last=first;
2557             while (isspace((int) ((unsigned char) *q)) != 0)
2558               q++;
2559             if (*q == '-')
2560               last=(size_t) strtol(q+1,&q,10);
2561             if (first > last)
2562               Swap(first,last);
2563             if (first < image_info->scene)
2564               image_info->scene=first;
2565             if (last > image_info->number_scenes)
2566               image_info->number_scenes=last;
2567             p=q;
2568           }
2569           image_info->number_scenes-=image_info->scene-1;
2570         }
2571     }
2572   *component='\0';
2573   if (*image_info->magick == '\0')
2574     GetPathComponent(image_info->filename,ExtensionPath,component);
2575 #if defined(MAGICKCORE_ZLIB_DELEGATE)
2576   if (*component != '\0')
2577     if ((LocaleCompare(component,"gz") == 0) ||
2578         (LocaleCompare(component,"Z") == 0) ||
2579         (LocaleCompare(component,"svgz") == 0) ||
2580         (LocaleCompare(component,"wmz") == 0))
2581       {
2582         char
2583           path[MagickPathExtent];
2584
2585         (void) CopyMagickString(path,image_info->filename,MagickPathExtent);
2586         path[strlen(path)-strlen(component)-1]='\0';
2587         GetPathComponent(path,ExtensionPath,component);
2588       }
2589 #endif
2590 #if defined(MAGICKCORE_BZLIB_DELEGATE)
2591   if (*component != '\0')
2592     if (LocaleCompare(component,"bz2") == 0)
2593       {
2594         char
2595           path[MagickPathExtent];
2596
2597         (void) CopyMagickString(path,image_info->filename,MagickPathExtent);
2598         path[strlen(path)-strlen(component)-1]='\0';
2599         GetPathComponent(path,ExtensionPath,component);
2600       }
2601 #endif
2602   image_info->affirm=MagickFalse;
2603   sans_exception=AcquireExceptionInfo();
2604   if (*component != '\0')
2605     {
2606       MagickFormatType
2607         format_type;
2608
2609       register ssize_t
2610         i;
2611
2612       static const char
2613         *format_type_formats[] =
2614         {
2615           "AUTOTRACE",
2616           "BROWSE",
2617           "DCRAW",
2618           "EDIT",
2619           "EPHEMERAL",
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           if (LocaleCompare(magic,"EPHEMERAL") != 0)
2685             image_info->affirm=MagickTrue;
2686           else
2687             image_info->temporary=MagickTrue;
2688         }
2689     }
2690   magick_info=GetMagickInfo(magic,sans_exception);
2691   sans_exception=DestroyExceptionInfo(sans_exception);
2692   if ((magick_info == (const MagickInfo *) NULL) ||
2693       (GetMagickEndianSupport(magick_info) == MagickFalse))
2694     image_info->endian=UndefinedEndian;
2695   GetPathComponent(image_info->filename,CanonicalPath,component);
2696   (void) CopyMagickString(image_info->filename,component,MagickPathExtent);
2697   if ((image_info->adjoin != MagickFalse) && (frames > 1))
2698     {
2699       /*
2700         Test for multiple image support (e.g. image%02d.png).
2701       */
2702       (void) InterpretImageFilename(image_info,(Image *) NULL,
2703         image_info->filename,(int) image_info->scene,component,exception);
2704       if ((LocaleCompare(component,image_info->filename) != 0) &&
2705           (strchr(component,'%') == (char *) NULL))
2706         image_info->adjoin=MagickFalse;
2707     }
2708   if ((image_info->adjoin != MagickFalse) && (frames > 0))
2709     {
2710       /*
2711         Some image formats do not support multiple frames per file.
2712       */
2713       magick_info=GetMagickInfo(magic,exception);
2714       if (magick_info != (const MagickInfo *) NULL)
2715         if (GetMagickAdjoin(magick_info) == MagickFalse)
2716           image_info->adjoin=MagickFalse;
2717     }
2718   if (image_info->affirm != MagickFalse)
2719     return(MagickTrue);
2720   if (frames == 0)
2721     {
2722       unsigned char
2723         *magick;
2724
2725       size_t
2726         magick_size;
2727
2728       /*
2729         Determine the image format from the first few bytes of the file.
2730       */
2731       magick_size=GetMagicPatternExtent(exception);
2732       if (magick_size == 0)
2733         return(MagickFalse);
2734       image=AcquireImage(image_info,exception);
2735       (void) CopyMagickString(image->filename,image_info->filename,
2736         MagickPathExtent);
2737       status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
2738       if (status == MagickFalse)
2739         {
2740           image=DestroyImage(image);
2741           return(MagickFalse);
2742         }
2743       if ((IsBlobSeekable(image) == MagickFalse) ||
2744           (IsBlobExempt(image) != MagickFalse))
2745         {
2746           /*
2747             Copy standard input or pipe to temporary file.
2748           */
2749           *component='\0';
2750           status=ImageToFile(image,component,exception);
2751           (void) CloseBlob(image);
2752           if (status == MagickFalse)
2753             {
2754               image=DestroyImage(image);
2755               return(MagickFalse);
2756             }
2757           SetImageInfoFile(image_info,(FILE *) NULL);
2758           (void) CopyMagickString(image->filename,component,MagickPathExtent);
2759           status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
2760           if (status == MagickFalse)
2761             {
2762               image=DestroyImage(image);
2763               return(MagickFalse);
2764             }
2765           (void) CopyMagickString(image_info->filename,component,
2766             MagickPathExtent);
2767           image_info->temporary=MagickTrue;
2768         }
2769       magick=(unsigned char *) AcquireMagickMemory(magick_size);
2770       if (magick == (unsigned char *) NULL)
2771         {
2772           (void) CloseBlob(image);
2773           image=DestroyImage(image);
2774           return(MagickFalse);
2775         }
2776       (void) ResetMagickMemory(magick,0,magick_size);
2777       count=ReadBlob(image,magick_size,magick);
2778       (void) SeekBlob(image,-((MagickOffsetType) count),SEEK_CUR);
2779       (void) CloseBlob(image);
2780       image=DestroyImage(image);
2781       /*
2782         Check magic.xml configuration file.
2783       */
2784       sans_exception=AcquireExceptionInfo();
2785       magic_info=GetMagicInfo(magick,(size_t) count,sans_exception);
2786       magick=(unsigned char *) RelinquishMagickMemory(magick);
2787       if ((magic_info != (const MagicInfo *) NULL) &&
2788           (GetMagicName(magic_info) != (char *) NULL))
2789         {
2790           /*
2791             Try to use magick_info that was determined earlier by the extension
2792           */
2793           if ((magick_info != (const MagickInfo *) NULL) &&
2794               (GetMagickUseExtension(magick_info) != MagickFalse) &&
2795               (LocaleCompare(magick_info->module,GetMagicName(
2796                 magic_info)) == 0))
2797             (void) CopyMagickString(image_info->magick,magick_info->name,
2798               MagickPathExtent);
2799           else
2800             {
2801               (void) CopyMagickString(image_info->magick,GetMagicName(
2802                 magic_info),MagickPathExtent);
2803               magick_info=GetMagickInfo(image_info->magick,sans_exception);
2804             }
2805           if ((magick_info == (const MagickInfo *) NULL) ||
2806               (GetMagickEndianSupport(magick_info) == MagickFalse))
2807             image_info->endian=UndefinedEndian;
2808           sans_exception=DestroyExceptionInfo(sans_exception);
2809           return(MagickTrue);
2810         }
2811       magick_info=GetMagickInfo(image_info->magick,sans_exception);
2812       if ((magick_info == (const MagickInfo *) NULL) ||
2813           (GetMagickEndianSupport(magick_info) == MagickFalse))
2814         image_info->endian=UndefinedEndian;
2815       sans_exception=DestroyExceptionInfo(sans_exception);
2816     }
2817   return(MagickTrue);
2818 }
2819 \f
2820 /*
2821 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2822 %                                                                             %
2823 %                                                                             %
2824 %                                                                             %
2825 %   S e t I m a g e I n f o B l o b                                           %
2826 %                                                                             %
2827 %                                                                             %
2828 %                                                                             %
2829 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2830 %
2831 %  SetImageInfoBlob() sets the image info blob member.
2832 %
2833 %  The format of the SetImageInfoBlob method is:
2834 %
2835 %      void SetImageInfoBlob(ImageInfo *image_info,const void *blob,
2836 %        const size_t length)
2837 %
2838 %  A description of each parameter follows:
2839 %
2840 %    o image_info: the image info.
2841 %
2842 %    o blob: the blob.
2843 %
2844 %    o length: the blob length.
2845 %
2846 */
2847 MagickExport void SetImageInfoBlob(ImageInfo *image_info,const void *blob,
2848   const size_t length)
2849 {
2850   assert(image_info != (ImageInfo *) NULL);
2851   assert(image_info->signature == MagickCoreSignature);
2852   if (image_info->debug != MagickFalse)
2853     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2854       image_info->filename);
2855   image_info->blob=(void *) blob;
2856   image_info->length=length;
2857 }
2858 \f
2859 /*
2860 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2861 %                                                                             %
2862 %                                                                             %
2863 %                                                                             %
2864 %   S e t I m a g e I n f o F i l e                                           %
2865 %                                                                             %
2866 %                                                                             %
2867 %                                                                             %
2868 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2869 %
2870 %  SetImageInfoFile() sets the image info file member.
2871 %
2872 %  The format of the SetImageInfoFile method is:
2873 %
2874 %      void SetImageInfoFile(ImageInfo *image_info,FILE *file)
2875 %
2876 %  A description of each parameter follows:
2877 %
2878 %    o image_info: the image info.
2879 %
2880 %    o file: the file.
2881 %
2882 */
2883 MagickExport void SetImageInfoFile(ImageInfo *image_info,FILE *file)
2884 {
2885   assert(image_info != (ImageInfo *) NULL);
2886   assert(image_info->signature == MagickCoreSignature);
2887   if (image_info->debug != MagickFalse)
2888     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2889       image_info->filename);
2890   image_info->file=file;
2891 }
2892 \f
2893 /*
2894 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2895 %                                                                             %
2896 %                                                                             %
2897 %                                                                             %
2898 %   S e t I m a g e M a s k                                                   %
2899 %                                                                             %
2900 %                                                                             %
2901 %                                                                             %
2902 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2903 %
2904 %  SetImageMask() associates a mask with the image.  The mask must be the same
2905 %  dimensions as the image.
2906 %
2907 %  The format of the SetImageMask method is:
2908 %
2909 %      MagickBooleanType SetImageMask(Image *image,const PixelMask type,
2910 %        const Image *mask,ExceptionInfo *exception)
2911 %
2912 %  A description of each parameter follows:
2913 %
2914 %    o image: the image.
2915 %
2916 %    o type: the mask type, ReadPixelMask or WritePixelMask.
2917 %
2918 %    o mask: the image mask.
2919 %
2920 %    o exception: return any errors or warnings in this structure.
2921 %
2922 */
2923 MagickExport MagickBooleanType SetImageMask(Image *image,const PixelMask type,
2924   const Image *mask,ExceptionInfo *exception)
2925 {
2926   CacheView
2927     *mask_view,
2928     *image_view;
2929
2930   MagickBooleanType
2931     status;
2932
2933   ssize_t
2934     y;
2935
2936   /*
2937     Set image mask.
2938   */
2939   assert(image != (Image *) NULL);
2940   if (image->debug != MagickFalse)
2941     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
2942   assert(image->signature == MagickCoreSignature);
2943   if (mask == (const Image *) NULL)
2944     {
2945       switch (type)
2946       {
2947         case WritePixelMask: image->write_mask=MagickFalse; break;
2948         default: image->read_mask=MagickFalse; break;
2949       }
2950       return(SyncImagePixelCache(image,exception));
2951     }
2952   switch (type)
2953   {
2954     case WritePixelMask: image->write_mask=MagickTrue; break;
2955     default: image->read_mask=MagickTrue; break;
2956   }
2957   if (SyncImagePixelCache(image,exception) == MagickFalse)
2958     return(MagickFalse);
2959   status=MagickTrue;
2960   mask_view=AcquireVirtualCacheView(mask,exception);
2961   image_view=AcquireAuthenticCacheView(image,exception);
2962 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2963   #pragma omp parallel for schedule(static,4) shared(status) \
2964     magick_threads(mask,image,1,1)
2965 #endif
2966   for (y=0; y < (ssize_t) image->rows; y++)
2967   {
2968     register const Quantum
2969       *magick_restrict p;
2970
2971     register Quantum
2972       *magick_restrict q;
2973
2974     register ssize_t
2975       x;
2976
2977     if (status == MagickFalse)
2978       continue;
2979     p=GetCacheViewVirtualPixels(mask_view,0,y,mask->columns,1,exception);
2980     q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
2981     if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
2982       {
2983         status=MagickFalse;
2984         continue;
2985       }
2986     for (x=0; x < (ssize_t) image->columns; x++)
2987     {
2988       MagickRealType
2989         intensity;
2990
2991       intensity=GetPixelIntensity(mask,p);
2992       switch (type)
2993       {
2994         case WritePixelMask:
2995         {
2996           SetPixelWriteMask(image,ClampToQuantum(QuantumRange-intensity),q);
2997           break;
2998         }
2999         default:
3000         {
3001           SetPixelReadMask(image,ClampToQuantum(QuantumRange-intensity),q);
3002           break;
3003         }
3004       }
3005       p+=GetPixelChannels(mask);
3006       q+=GetPixelChannels(image);
3007     }
3008     if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
3009       status=MagickFalse;
3010   }
3011   mask_view=DestroyCacheView(mask_view);
3012   image_view=DestroyCacheView(image_view);
3013   return(status);
3014 }
3015 \f
3016 /*
3017 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3018 %                                                                             %
3019 %                                                                             %
3020 %                                                                             %
3021 %     S e t I m a g e A l p h a                                               %
3022 %                                                                             %
3023 %                                                                             %
3024 %                                                                             %
3025 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3026 %
3027 %  SetImageAlpha() sets the alpha levels of the image.
3028 %
3029 %  The format of the SetImageAlpha method is:
3030 %
3031 %      MagickBooleanType SetImageAlpha(Image *image,const Quantum alpha,
3032 %        ExceptionInfo *exception)
3033 %
3034 %  A description of each parameter follows:
3035 %
3036 %    o image: the image.
3037 %
3038 %    o Alpha: the level of transparency: 0 is fully opaque and QuantumRange is
3039 %      fully transparent.
3040 %
3041 */
3042 MagickExport MagickBooleanType SetImageAlpha(Image *image,const Quantum alpha,
3043   ExceptionInfo *exception)
3044 {
3045   CacheView
3046     *image_view;
3047
3048   MagickBooleanType
3049     status;
3050
3051   ssize_t
3052     y;
3053
3054   assert(image != (Image *) NULL);
3055   if (image->debug != MagickFalse)
3056     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
3057   assert(image->signature == MagickCoreSignature);
3058   image->alpha_trait=BlendPixelTrait;
3059   status=MagickTrue;
3060   image_view=AcquireAuthenticCacheView(image,exception);
3061 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3062   #pragma omp parallel for schedule(static,4) shared(status) \
3063     magick_threads(image,image,image->rows,1)
3064 #endif
3065   for (y=0; y < (ssize_t) image->rows; y++)
3066   {
3067     register Quantum
3068       *magick_restrict q;
3069
3070     register ssize_t
3071       x;
3072
3073     if (status == MagickFalse)
3074       continue;
3075     q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
3076     if (q == (Quantum *) NULL)
3077       {
3078         status=MagickFalse;
3079         continue;
3080       }
3081     for (x=0; x < (ssize_t) image->columns; x++)
3082     {
3083       if (GetPixelReadMask(image,q) != 0)
3084         SetPixelAlpha(image,alpha,q);
3085       q+=GetPixelChannels(image);
3086     }
3087     if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
3088       status=MagickFalse;
3089   }
3090   image_view=DestroyCacheView(image_view);
3091   return(status);
3092 }
3093 \f
3094 /*
3095 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3096 %                                                                             %
3097 %                                                                             %
3098 %                                                                             %
3099 %   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                       %
3100 %                                                                             %
3101 %                                                                             %
3102 %                                                                             %
3103 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3104 %
3105 %  SetImageVirtualPixelMethod() sets the "virtual pixels" method for the
3106 %  image and returns the previous setting.  A virtual pixel is any pixel access
3107 %  that is outside the boundaries of the image cache.
3108 %
3109 %  The format of the SetImageVirtualPixelMethod() method is:
3110 %
3111 %      VirtualPixelMethod SetImageVirtualPixelMethod(Image *image,
3112 %        const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
3113 %
3114 %  A description of each parameter follows:
3115 %
3116 %    o image: the image.
3117 %
3118 %    o virtual_pixel_method: choose the type of virtual pixel.
3119 %
3120 %    o exception: return any errors or warnings in this structure.
3121 %
3122 */
3123 MagickExport VirtualPixelMethod SetImageVirtualPixelMethod(Image *image,
3124   const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
3125 {
3126   assert(image != (const Image *) NULL);
3127   assert(image->signature == MagickCoreSignature);
3128   if (image->debug != MagickFalse)
3129     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3130   return(SetPixelCacheVirtualMethod(image,virtual_pixel_method,exception));
3131 }
3132 \f
3133 /*
3134 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3135 %                                                                             %
3136 %                                                                             %
3137 %                                                                             %
3138 %     S m u s h I m a g e s                                                   %
3139 %                                                                             %
3140 %                                                                             %
3141 %                                                                             %
3142 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3143 %
3144 %  SmushImages() takes all images from the current image pointer to the end
3145 %  of the image list and smushes them to each other top-to-bottom if the
3146 %  stack parameter is true, otherwise left-to-right.
3147 %
3148 %  The current gravity setting now effects how the image is justified in the
3149 %  final image.
3150 %
3151 %  The format of the SmushImages method is:
3152 %
3153 %      Image *SmushImages(const Image *images,const MagickBooleanType stack,
3154 %        ExceptionInfo *exception)
3155 %
3156 %  A description of each parameter follows:
3157 %
3158 %    o images: the image sequence.
3159 %
3160 %    o stack: A value other than 0 stacks the images top-to-bottom.
3161 %
3162 %    o offset: minimum distance in pixels between images.
3163 %
3164 %    o exception: return any errors or warnings in this structure.
3165 %
3166 */
3167
3168 static ssize_t SmushXGap(const Image *smush_image,const Image *images,
3169   const ssize_t offset,ExceptionInfo *exception)
3170 {
3171   CacheView
3172     *left_view,
3173     *right_view;
3174
3175   const Image
3176     *left_image,
3177     *right_image;
3178
3179   RectangleInfo
3180     left_geometry,
3181     right_geometry;
3182
3183   register const Quantum
3184     *p;
3185
3186   register ssize_t
3187     i,
3188     y;
3189
3190   size_t
3191     gap;
3192
3193   ssize_t
3194     x;
3195
3196   if (images->previous == (Image *) NULL)
3197     return(0);
3198   right_image=images;
3199   SetGeometry(smush_image,&right_geometry);
3200   GravityAdjustGeometry(right_image->columns,right_image->rows,
3201     right_image->gravity,&right_geometry);
3202   left_image=images->previous;
3203   SetGeometry(smush_image,&left_geometry);
3204   GravityAdjustGeometry(left_image->columns,left_image->rows,
3205     left_image->gravity,&left_geometry);
3206   gap=right_image->columns;
3207   left_view=AcquireVirtualCacheView(left_image,exception);
3208   right_view=AcquireVirtualCacheView(right_image,exception);
3209   for (y=0; y < (ssize_t) smush_image->rows; y++)
3210   {
3211     for (x=(ssize_t) left_image->columns-1; x > 0; x--)
3212     {
3213       p=GetCacheViewVirtualPixels(left_view,x,left_geometry.y+y,1,1,exception);
3214       if ((p == (const Quantum *) NULL) ||
3215           (GetPixelAlpha(left_image,p) != TransparentAlpha) ||
3216           ((left_image->columns-x-1) >= gap))
3217         break;
3218     }
3219     i=(ssize_t) left_image->columns-x-1;
3220     for (x=0; x < (ssize_t) right_image->columns; x++)
3221     {
3222       p=GetCacheViewVirtualPixels(right_view,x,right_geometry.y+y,1,1,
3223         exception);
3224       if ((p == (const Quantum *) NULL) ||
3225           (GetPixelAlpha(right_image,p) != TransparentAlpha) ||
3226           ((x+i) >= (ssize_t) gap))
3227         break;
3228     }
3229     if ((x+i) < (ssize_t) gap)
3230       gap=(size_t) (x+i);
3231   }
3232   right_view=DestroyCacheView(right_view);
3233   left_view=DestroyCacheView(left_view);
3234   if (y < (ssize_t) smush_image->rows)
3235     return(offset);
3236   return((ssize_t) gap-offset);
3237 }
3238
3239 static ssize_t SmushYGap(const Image *smush_image,const Image *images,
3240   const ssize_t offset,ExceptionInfo *exception)
3241 {
3242   CacheView
3243     *bottom_view,
3244     *top_view;
3245
3246   const Image
3247     *bottom_image,
3248     *top_image;
3249
3250   RectangleInfo
3251     bottom_geometry,
3252     top_geometry;
3253
3254   register const Quantum
3255     *p;
3256
3257   register ssize_t
3258     i,
3259     x;
3260
3261   size_t
3262     gap;
3263
3264   ssize_t
3265     y;
3266
3267   if (images->previous == (Image *) NULL)
3268     return(0);
3269   bottom_image=images;
3270   SetGeometry(smush_image,&bottom_geometry);
3271   GravityAdjustGeometry(bottom_image->columns,bottom_image->rows,
3272     bottom_image->gravity,&bottom_geometry);
3273   top_image=images->previous;
3274   SetGeometry(smush_image,&top_geometry);
3275   GravityAdjustGeometry(top_image->columns,top_image->rows,top_image->gravity,
3276     &top_geometry);
3277   gap=bottom_image->rows;
3278   top_view=AcquireVirtualCacheView(top_image,exception);
3279   bottom_view=AcquireVirtualCacheView(bottom_image,exception);
3280   for (x=0; x < (ssize_t) smush_image->columns; x++)
3281   {
3282     for (y=(ssize_t) top_image->rows-1; y > 0; y--)
3283     {
3284       p=GetCacheViewVirtualPixels(top_view,top_geometry.x+x,y,1,1,exception);
3285       if ((p == (const Quantum *) NULL) ||
3286           (GetPixelAlpha(top_image,p) != TransparentAlpha) ||
3287           ((top_image->rows-y-1) >= gap))
3288         break;
3289     }
3290     i=(ssize_t) top_image->rows-y-1;
3291     for (y=0; y < (ssize_t) bottom_image->rows; y++)
3292     {
3293       p=GetCacheViewVirtualPixels(bottom_view,bottom_geometry.x+x,y,1,1,
3294         exception);
3295       if ((p == (const Quantum *) NULL) ||
3296           (GetPixelAlpha(bottom_image,p) != TransparentAlpha) ||
3297           ((y+i) >= (ssize_t) gap))
3298         break;
3299     }
3300     if ((y+i) < (ssize_t) gap)
3301       gap=(size_t) (y+i);
3302   }
3303   bottom_view=DestroyCacheView(bottom_view);
3304   top_view=DestroyCacheView(top_view);
3305   if (x < (ssize_t) smush_image->columns)
3306     return(offset);
3307   return((ssize_t) gap-offset);
3308 }
3309
3310 MagickExport Image *SmushImages(const Image *images,
3311   const MagickBooleanType stack,const ssize_t offset,ExceptionInfo *exception)
3312 {
3313 #define SmushImageTag  "Smush/Image"
3314
3315   const Image
3316     *image;
3317
3318   Image
3319     *smush_image;
3320
3321   MagickBooleanType
3322     proceed,
3323     status;
3324
3325   MagickOffsetType
3326     n;
3327
3328   PixelTrait
3329     alpha_trait;
3330
3331   RectangleInfo
3332     geometry;
3333
3334   register const Image
3335     *next;
3336
3337   size_t
3338     height,
3339     number_images,
3340     width;
3341
3342   ssize_t
3343     x_offset,
3344     y_offset;
3345
3346   /*
3347     Compute maximum area of smushed area.
3348   */
3349   assert(images != (Image *) NULL);
3350   assert(images->signature == MagickCoreSignature);
3351   if (images->debug != MagickFalse)
3352     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
3353   assert(exception != (ExceptionInfo *) NULL);
3354   assert(exception->signature == MagickCoreSignature);
3355   image=images;
3356   alpha_trait=image->alpha_trait;
3357   number_images=1;
3358   width=image->columns;
3359   height=image->rows;
3360   next=GetNextImageInList(image);
3361   for ( ; next != (Image *) NULL; next=GetNextImageInList(next))
3362   {
3363     if (next->alpha_trait != UndefinedPixelTrait)
3364       alpha_trait=BlendPixelTrait;
3365     number_images++;
3366     if (stack != MagickFalse)
3367       {
3368         if (next->columns > width)
3369           width=next->columns;
3370         height+=next->rows;
3371         if (next->previous != (Image *) NULL)
3372           height+=offset;
3373         continue;
3374       }
3375     width+=next->columns;
3376     if (next->previous != (Image *) NULL)
3377       width+=offset;
3378     if (next->rows > height)
3379       height=next->rows;
3380   }
3381   /*
3382     Smush images.
3383   */
3384   smush_image=CloneImage(image,width,height,MagickTrue,exception);
3385   if (smush_image == (Image *) NULL)
3386     return((Image *) NULL);
3387   if (SetImageStorageClass(smush_image,DirectClass,exception) == MagickFalse)
3388     {
3389       smush_image=DestroyImage(smush_image);
3390       return((Image *) NULL);
3391     }
3392   smush_image->alpha_trait=alpha_trait;
3393   (void) SetImageBackgroundColor(smush_image,exception);
3394   status=MagickTrue;
3395   x_offset=0;
3396   y_offset=0;
3397   for (n=0; n < (MagickOffsetType) number_images; n++)
3398   {
3399     SetGeometry(smush_image,&geometry);
3400     GravityAdjustGeometry(image->columns,image->rows,image->gravity,&geometry);
3401     if (stack != MagickFalse)
3402       {
3403         x_offset-=geometry.x;
3404         y_offset-=SmushYGap(smush_image,image,offset,exception);
3405       }
3406     else
3407       {
3408         x_offset-=SmushXGap(smush_image,image,offset,exception);
3409         y_offset-=geometry.y;
3410       }
3411     status=CompositeImage(smush_image,image,OverCompositeOp,MagickTrue,x_offset,
3412       y_offset,exception);
3413     proceed=SetImageProgress(image,SmushImageTag,n,number_images);
3414     if (proceed == MagickFalse)
3415       break;
3416     if (stack == MagickFalse)
3417       {
3418         x_offset+=(ssize_t) image->columns;
3419         y_offset=0;
3420       }
3421     else
3422       {
3423         x_offset=0;
3424         y_offset+=(ssize_t) image->rows;
3425       }
3426     image=GetNextImageInList(image);
3427   }
3428   if (stack == MagickFalse)
3429     smush_image->columns=(size_t) x_offset;
3430   else
3431     smush_image->rows=(size_t) y_offset;
3432   if (status == MagickFalse)
3433     smush_image=DestroyImage(smush_image);
3434   return(smush_image);
3435 }
3436 \f
3437 /*
3438 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3439 %                                                                             %
3440 %                                                                             %
3441 %                                                                             %
3442 %   S t r i p I m a g e                                                       %
3443 %                                                                             %
3444 %                                                                             %
3445 %                                                                             %
3446 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3447 %
3448 %  StripImage() strips an image of all profiles and comments.
3449 %
3450 %  The format of the StripImage method is:
3451 %
3452 %      MagickBooleanType StripImage(Image *image,ExceptionInfo *exception)
3453 %
3454 %  A description of each parameter follows:
3455 %
3456 %    o image: the image.
3457 %
3458 %    o exception: return any errors or warnings in this structure.
3459 %
3460 */
3461 MagickExport MagickBooleanType StripImage(Image *image,ExceptionInfo *exception)
3462 {
3463   MagickBooleanType
3464     status;
3465
3466   assert(image != (Image *) NULL);
3467   if (image->debug != MagickFalse)
3468     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
3469   (void) exception;
3470   DestroyImageProfiles(image);
3471   (void) DeleteImageProperty(image,"comment");
3472   (void) DeleteImageProperty(image,"date:create");
3473   (void) DeleteImageProperty(image,"date:modify");
3474   status=SetImageArtifact(image,"png:exclude-chunk",
3475     "cHRM,EXIF,gAMA,iCCP,iTXt,sRGB,tEXt,zCCP,zTXt,date");
3476   return(status);
3477 }
3478 \f
3479 /*
3480 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3481 %                                                                             %
3482 %                                                                             %
3483 %                                                                             %
3484 +   S y n c I m a g e                                                         %
3485 %                                                                             %
3486 %                                                                             %
3487 %                                                                             %
3488 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3489 %
3490 %  SyncImage() initializes the red, green, and blue intensities of each pixel
3491 %  as defined by the colormap index.
3492 %
3493 %  The format of the SyncImage method is:
3494 %
3495 %      MagickBooleanType SyncImage(Image *image,ExceptionInfo *exception)
3496 %
3497 %  A description of each parameter follows:
3498 %
3499 %    o image: the image.
3500 %
3501 %    o exception: return any errors or warnings in this structure.
3502 %
3503 */
3504
3505 static inline Quantum PushColormapIndex(Image *image,const Quantum index,
3506   MagickBooleanType *range_exception)
3507 {
3508   if ((size_t) index < image->colors)
3509     return(index);
3510   *range_exception=MagickTrue;
3511   return((Quantum) 0);
3512 }
3513
3514 MagickExport MagickBooleanType SyncImage(Image *image,ExceptionInfo *exception)
3515 {
3516   CacheView
3517     *image_view;
3518
3519   MagickBooleanType
3520     range_exception,
3521     status,
3522     taint;
3523
3524   ssize_t
3525     y;
3526
3527   assert(image != (Image *) NULL);
3528   if (image->debug != MagickFalse)
3529     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
3530   assert(image->signature == MagickCoreSignature);
3531   if (image->storage_class == DirectClass)
3532     return(MagickFalse);
3533   range_exception=MagickFalse;
3534   status=MagickTrue;
3535   taint=image->taint;
3536   image_view=AcquireAuthenticCacheView(image,exception);
3537 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3538   #pragma omp parallel for schedule(static,4) shared(range_exception,status) \
3539     magick_threads(image,image,image->rows,1)
3540 #endif
3541   for (y=0; y < (ssize_t) image->rows; y++)
3542   {
3543     Quantum
3544       index;
3545
3546     register Quantum
3547       *magick_restrict q;
3548
3549     register ssize_t
3550       x;
3551
3552     if (status == MagickFalse)
3553       continue;
3554     q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
3555     if (q == (Quantum *) NULL)
3556       {
3557         status=MagickFalse;
3558         continue;
3559       }
3560     for (x=0; x < (ssize_t) image->columns; x++)
3561     {
3562       index=PushColormapIndex(image,GetPixelIndex(image,q),&range_exception);
3563       SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q);
3564       q+=GetPixelChannels(image);
3565     }
3566     if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
3567       status=MagickFalse;
3568   }
3569   image_view=DestroyCacheView(image_view);
3570   image->taint=taint;
3571   if ((image->ping == MagickFalse) && (range_exception != MagickFalse))
3572     (void) ThrowMagickException(exception,GetMagickModule(),
3573       CorruptImageWarning,"InvalidColormapIndex","`%s'",image->filename);
3574   return(status);
3575 }
3576 \f
3577 /*
3578 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3579 %                                                                             %
3580 %                                                                             %
3581 %                                                                             %
3582 %   S y n c I m a g e S e t t i n g s                                         %
3583 %                                                                             %
3584 %                                                                             %
3585 %                                                                             %
3586 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3587 %
3588 %  SyncImageSettings() syncs any image_info global options into per-image
3589 %  attributes.
3590 %
3591 %  Note: in IMv6 free form 'options' were always mapped into 'artifacts', so
3592 %  that operations and coders can find such settings.  In IMv7 if a desired
3593 %  per-image artifact is not set, then it will directly look for a global
3594 %  option as a fallback, as such this copy is no longer needed, only the
3595 %  link set up.
3596 %
3597 %  The format of the SyncImageSettings method is:
3598 %
3599 %      MagickBooleanType SyncImageSettings(const ImageInfo *image_info,
3600 %        Image *image,ExceptionInfo *exception)
3601 %      MagickBooleanType SyncImagesSettings(const ImageInfo *image_info,
3602 %        Image *image,ExceptionInfo *exception)
3603 %
3604 %  A description of each parameter follows:
3605 %
3606 %    o image_info: the image info.
3607 %
3608 %    o image: the image.
3609 %
3610 %    o exception: return any errors or warnings in this structure.
3611 %
3612 */
3613
3614 MagickExport MagickBooleanType SyncImagesSettings(ImageInfo *image_info,
3615   Image *images,ExceptionInfo *exception)
3616 {
3617   Image
3618     *image;
3619
3620   assert(image_info != (const ImageInfo *) NULL);
3621   assert(image_info->signature == MagickCoreSignature);
3622   assert(images != (Image *) NULL);
3623   assert(images->signature == MagickCoreSignature);
3624   if (images->debug != MagickFalse)
3625     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
3626   image=images;
3627   for ( ; image != (Image *) NULL; image=GetNextImageInList(image))
3628     (void) SyncImageSettings(image_info,image,exception);
3629   (void) DeleteImageOption(image_info,"page");
3630   return(MagickTrue);
3631 }
3632
3633 MagickExport MagickBooleanType SyncImageSettings(const ImageInfo *image_info,
3634   Image *image,ExceptionInfo *exception)
3635 {
3636   const char
3637     *option;
3638
3639   GeometryInfo
3640     geometry_info;
3641
3642   MagickStatusType
3643     flags;
3644
3645   ResolutionType
3646     units;
3647
3648   /*
3649     Sync image options.
3650   */
3651   assert(image_info != (const ImageInfo *) NULL);
3652   assert(image_info->signature == MagickCoreSignature);
3653   assert(image != (Image *) NULL);
3654   assert(image->signature == MagickCoreSignature);
3655   if (image->debug != MagickFalse)
3656     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3657   option=GetImageOption(image_info,"alpha-color");
3658   if (option != (const char *) NULL)
3659     (void) QueryColorCompliance(option,AllCompliance,&image->alpha_color,
3660       exception);
3661   option=GetImageOption(image_info,"background");
3662   if (option != (const char *) NULL)
3663     (void) QueryColorCompliance(option,AllCompliance,&image->background_color,
3664       exception);
3665   option=GetImageOption(image_info,"black-point-compensation");
3666   if (option != (const char *) NULL)
3667     image->black_point_compensation=(MagickBooleanType) ParseCommandOption(
3668       MagickBooleanOptions,MagickFalse,option);
3669   option=GetImageOption(image_info,"blue-primary");
3670   if (option != (const char *) NULL)
3671     {
3672       flags=ParseGeometry(option,&geometry_info);
3673       image->chromaticity.blue_primary.x=geometry_info.rho;
3674       image->chromaticity.blue_primary.y=geometry_info.sigma;
3675       if ((flags & SigmaValue) == 0)
3676         image->chromaticity.blue_primary.y=image->chromaticity.blue_primary.x;
3677     }
3678   option=GetImageOption(image_info,"bordercolor");
3679   if (option != (const char *) NULL)
3680     (void) QueryColorCompliance(option,AllCompliance,&image->border_color,
3681       exception);
3682   /* FUTURE: do not sync compose to per-image compose setting here */
3683   option=GetImageOption(image_info,"compose");
3684   if (option != (const char *) NULL)
3685     image->compose=(CompositeOperator) ParseCommandOption(MagickComposeOptions,
3686       MagickFalse,option);
3687   /* -- */
3688   option=GetImageOption(image_info,"compress");
3689   if (option != (const char *) NULL)
3690     image->compression=(CompressionType) ParseCommandOption(
3691       MagickCompressOptions,MagickFalse,option);
3692   option=GetImageOption(image_info,"debug");
3693   if (option != (const char *) NULL)
3694     image->debug=(MagickBooleanType) ParseCommandOption(MagickBooleanOptions,
3695       MagickFalse,option);
3696   option=GetImageOption(image_info,"density");
3697   if (option != (const char *) NULL)
3698     {
3699       GeometryInfo
3700         geometry_info;
3701
3702       flags=ParseGeometry(option,&geometry_info);
3703       image->resolution.x=geometry_info.rho;
3704       image->resolution.y=geometry_info.sigma;
3705       if ((flags & SigmaValue) == 0)
3706         image->resolution.y=image->resolution.x;
3707     }
3708   option=GetImageOption(image_info,"depth");
3709   if (option != (const char *) NULL)
3710     image->depth=StringToUnsignedLong(option);
3711   option=GetImageOption(image_info,"endian");
3712   if (option != (const char *) NULL)
3713     image->endian=(EndianType) ParseCommandOption(MagickEndianOptions,
3714       MagickFalse,option);
3715   option=GetImageOption(image_info,"filter");
3716   if (option != (const char *) NULL)
3717     image->filter=(FilterType) ParseCommandOption(MagickFilterOptions,
3718       MagickFalse,option);
3719   option=GetImageOption(image_info,"fuzz");
3720   if (option != (const char *) NULL)
3721     image->fuzz=StringToDoubleInterval(option,(double) QuantumRange+1.0);
3722   option=GetImageOption(image_info,"gravity");
3723   if (option != (const char *) NULL)
3724     image->gravity=(GravityType) ParseCommandOption(MagickGravityOptions,
3725       MagickFalse,option);
3726   option=GetImageOption(image_info,"green-primary");
3727   if (option != (const char *) NULL)
3728     {
3729       flags=ParseGeometry(option,&geometry_info);
3730       image->chromaticity.green_primary.x=geometry_info.rho;
3731       image->chromaticity.green_primary.y=geometry_info.sigma;
3732       if ((flags & SigmaValue) == 0)
3733         image->chromaticity.green_primary.y=image->chromaticity.green_primary.x;
3734     }
3735   option=GetImageOption(image_info,"intent");
3736   if (option != (const char *) NULL)
3737     image->rendering_intent=(RenderingIntent) ParseCommandOption(
3738       MagickIntentOptions,MagickFalse,option);
3739   option=GetImageOption(image_info,"intensity");
3740   if (option != (const char *) NULL)
3741     image->intensity=(PixelIntensityMethod) ParseCommandOption(
3742       MagickPixelIntensityOptions,MagickFalse,option);
3743   option=GetImageOption(image_info,"interlace");
3744   if (option != (const char *) NULL)
3745     image->interlace=(InterlaceType) ParseCommandOption(MagickInterlaceOptions,
3746       MagickFalse,option);
3747   option=GetImageOption(image_info,"interpolate");
3748   if (option != (const char *) NULL)
3749     image->interpolate=(PixelInterpolateMethod) ParseCommandOption(
3750       MagickInterpolateOptions,MagickFalse,option);
3751   option=GetImageOption(image_info,"loop");
3752   if (option != (const char *) NULL)
3753     image->iterations=StringToUnsignedLong(option);
3754   option=GetImageOption(image_info,"orient");
3755   if (option != (const char *) NULL)
3756     image->orientation=(OrientationType) ParseCommandOption(
3757       MagickOrientationOptions,MagickFalse,option);
3758   option=GetImageOption(image_info,"page");
3759   if (option != (const char *) NULL)
3760     {
3761       char
3762         *geometry;
3763
3764       geometry=GetPageGeometry(option);
3765       flags=ParseAbsoluteGeometry(geometry,&image->page);
3766       geometry=DestroyString(geometry);
3767     }
3768   option=GetImageOption(image_info,"quality");
3769   if (option != (const char *) NULL)
3770     image->quality=StringToUnsignedLong(option);
3771   option=GetImageOption(image_info,"red-primary");
3772   if (option != (const char *) NULL)
3773     {
3774       flags=ParseGeometry(option,&geometry_info);
3775       image->chromaticity.red_primary.x=geometry_info.rho;
3776       image->chromaticity.red_primary.y=geometry_info.sigma;
3777       if ((flags & SigmaValue) == 0)
3778         image->chromaticity.red_primary.y=image->chromaticity.red_primary.x;
3779     }
3780   if (image_info->quality != UndefinedCompressionQuality)
3781     image->quality=image_info->quality;
3782   option=GetImageOption(image_info,"scene");
3783   if (option != (const char *) NULL)
3784     image->scene=StringToUnsignedLong(option);
3785   option=GetImageOption(image_info,"taint");
3786   if (option != (const char *) NULL)
3787     image->taint=(MagickBooleanType) ParseCommandOption(MagickBooleanOptions,
3788       MagickFalse,option);
3789   option=GetImageOption(image_info,"tile-offset");
3790   if (option != (const char *) NULL)
3791     {
3792       char
3793         *geometry;
3794
3795       geometry=GetPageGeometry(option);
3796       flags=ParseAbsoluteGeometry(geometry,&image->tile_offset);
3797       geometry=DestroyString(geometry);
3798     }
3799   option=GetImageOption(image_info,"transparent-color");
3800   if (option != (const char *) NULL)
3801     (void) QueryColorCompliance(option,AllCompliance,&image->transparent_color,
3802       exception);
3803   option=GetImageOption(image_info,"type");
3804   if (option != (const char *) NULL)
3805     image->type=(ImageType) ParseCommandOption(MagickTypeOptions,MagickFalse,
3806       option);
3807   option=GetImageOption(image_info,"units");
3808   units=image_info->units;
3809   if (option != (const char *) NULL)
3810     units=(ResolutionType) ParseCommandOption(MagickResolutionOptions,
3811       MagickFalse,option);
3812   if (units != UndefinedResolution)
3813     {
3814       if (image->units != units)
3815         switch (image->units)
3816         {
3817           case PixelsPerInchResolution:
3818           {
3819             if (units == PixelsPerCentimeterResolution)
3820               {
3821                 image->resolution.x/=2.54;
3822                 image->resolution.y/=2.54;
3823               }
3824             break;
3825           }
3826           case PixelsPerCentimeterResolution:
3827           {
3828             if (units == PixelsPerInchResolution)
3829               {
3830                 image->resolution.x=(double) ((size_t) (100.0*2.54*
3831                   image->resolution.x+0.5))/100.0;
3832                 image->resolution.y=(double) ((size_t) (100.0*2.54*
3833                   image->resolution.y+0.5))/100.0;
3834               }
3835             break;
3836           }
3837           default:
3838             break;
3839         }
3840       image->units=units;
3841     }
3842   option=GetImageOption(image_info,"virtual-pixel");
3843   if (option != (const char *) NULL)
3844     (void) SetImageVirtualPixelMethod(image,(VirtualPixelMethod)
3845       ParseCommandOption(MagickVirtualPixelOptions,MagickFalse,option),
3846       exception);
3847   option=GetImageOption(image_info,"white-point");
3848   if (option != (const char *) NULL)
3849     {
3850       flags=ParseGeometry(option,&geometry_info);
3851       image->chromaticity.white_point.x=geometry_info.rho;
3852       image->chromaticity.white_point.y=geometry_info.sigma;
3853       if ((flags & SigmaValue) == 0)
3854         image->chromaticity.white_point.y=image->chromaticity.white_point.x;
3855     }
3856   /*
3857     Pointer to allow the lookup of pre-image artifact will fallback to a global
3858     option setting/define.  This saves a lot of duplication of global options
3859     into per-image artifacts, while ensuring only specifically set per-image
3860     artifacts are preserved when parenthesis ends.
3861   */
3862   if (image->image_info != (ImageInfo *) NULL)
3863     image->image_info=DestroyImageInfo(image->image_info);
3864   image->image_info=CloneImageInfo(image_info);
3865   return(MagickTrue);
3866 }