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