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