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