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