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