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