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