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