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