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