• 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-2020 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/timer-private.h"
100 #include "MagickCore/token.h"
101 #include "MagickCore/token-private.h"
102 #include "MagickCore/utility.h"
103 #include "MagickCore/utility-private.h"
104 #include "MagickCore/version.h"
105 #include "MagickCore/xwindow-private.h"
106 
107 /*
108   Constant declaration.
109 */
110 const char
111   BackgroundColor[] = "#ffffff",  /* white */
112   BorderColor[] = "#dfdfdf",  /* gray */
113   DefaultTileFrame[] = "15x15+3+3",
114   DefaultTileGeometry[] = "120x120+4+3>",
115   DefaultTileLabel[] = "%f\n%G\n%b",
116   ForegroundColor[] = "#000",  /* black */
117   LoadImageTag[] = "Load/Image",
118   LoadImagesTag[] = "Load/Images",
119   MatteColor[] = "#bdbdbd",  /* gray */
120   PSDensityGeometry[] = "72.0x72.0",
121   PSPageGeometry[] = "612x792",
122   SaveImageTag[] = "Save/Image",
123   SaveImagesTag[] = "Save/Images",
124   TransparentColor[] = "#00000000";  /* transparent black */
125 
126 const double
127   DefaultResolution = 72.0;
128 
129 /*
130 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
131 %                                                                             %
132 %                                                                             %
133 %                                                                             %
134 %   A c q u i r e I m a g e                                                   %
135 %                                                                             %
136 %                                                                             %
137 %                                                                             %
138 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
139 %
140 %  AcquireImage() returns a pointer to an image structure initialized to
141 %  default values.
142 %
143 %  The format of the AcquireImage method is:
144 %
145 %      Image *AcquireImage(const ImageInfo *image_info,ExceptionInfo *exception)
146 %
147 %  A description of each parameter follows:
148 %
149 %    o image_info: Many of the image default values are set from this
150 %      structure.  For example, filename, compression, depth, background color,
151 %      and others.
152 %
153 %    o exception: return any errors or warnings in this structure.
154 %
155 */
AcquireImage(const ImageInfo * image_info,ExceptionInfo * exception)156 MagickExport Image *AcquireImage(const ImageInfo *image_info,
157   ExceptionInfo *exception)
158 {
159   const char
160     *option;
161 
162   Image
163     *image;
164 
165   MagickStatusType
166     flags;
167 
168   /*
169     Allocate image structure.
170   */
171   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
172   image=(Image *) AcquireCriticalMemory(sizeof(*image));
173   (void) memset(image,0,sizeof(*image));
174   /*
175     Initialize Image structure.
176   */
177   (void) CopyMagickString(image->magick,"MIFF",MagickPathExtent);
178   image->storage_class=DirectClass;
179   image->depth=MAGICKCORE_QUANTUM_DEPTH;
180   image->colorspace=sRGBColorspace;
181   image->rendering_intent=PerceptualIntent;
182   image->gamma=1.000f/2.200f;
183   image->chromaticity.red_primary.x=0.6400f;
184   image->chromaticity.red_primary.y=0.3300f;
185   image->chromaticity.red_primary.z=0.0300f;
186   image->chromaticity.green_primary.x=0.3000f;
187   image->chromaticity.green_primary.y=0.6000f;
188   image->chromaticity.green_primary.z=0.1000f;
189   image->chromaticity.blue_primary.x=0.1500f;
190   image->chromaticity.blue_primary.y=0.0600f;
191   image->chromaticity.blue_primary.z=0.7900f;
192   image->chromaticity.white_point.x=0.3127f;
193   image->chromaticity.white_point.y=0.3290f;
194   image->chromaticity.white_point.z=0.3583f;
195   image->interlace=NoInterlace;
196   image->ticks_per_second=UndefinedTicksPerSecond;
197   image->compose=OverCompositeOp;
198   (void) QueryColorCompliance(MatteColor,AllCompliance,&image->matte_color,
199     exception);
200   (void) QueryColorCompliance(BackgroundColor,AllCompliance,
201     &image->background_color,exception);
202   (void) QueryColorCompliance(BorderColor,AllCompliance,&image->border_color,
203     exception);
204   (void) QueryColorCompliance(TransparentColor,AllCompliance,
205     &image->transparent_color,exception);
206   GetTimerInfo(&image->timer);
207   image->cache=AcquirePixelCache(0);
208   image->channel_mask=DefaultChannels;
209   image->channel_map=AcquirePixelChannelMap();
210   image->blob=CloneBlobInfo((BlobInfo *) NULL);
211   image->timestamp=GetMagickTime();
212   image->debug=IsEventLogging();
213   image->reference_count=1;
214   image->semaphore=AcquireSemaphoreInfo();
215   image->signature=MagickCoreSignature;
216   if (image_info == (ImageInfo *) NULL)
217     return(image);
218   /*
219     Transfer image info.
220   */
221   SetBlobExempt(image,image_info->file != (FILE *) NULL ? MagickTrue :
222     MagickFalse);
223   (void) CopyMagickString(image->filename,image_info->filename,
224     MagickPathExtent);
225   (void) CopyMagickString(image->magick_filename,image_info->filename,
226     MagickPathExtent);
227   (void) CopyMagickString(image->magick,image_info->magick,MagickPathExtent);
228   if (image_info->size != (char *) NULL)
229     {
230       (void) ParseAbsoluteGeometry(image_info->size,&image->extract_info);
231       image->columns=image->extract_info.width;
232       image->rows=image->extract_info.height;
233       image->offset=image->extract_info.x;
234       image->extract_info.x=0;
235       image->extract_info.y=0;
236     }
237   if (image_info->extract != (char *) NULL)
238     {
239       RectangleInfo
240         geometry;
241 
242       (void) memset(&geometry,0,sizeof(geometry));
243       flags=ParseAbsoluteGeometry(image_info->extract,&geometry);
244       if (((flags & XValue) != 0) || ((flags & YValue) != 0))
245         {
246           image->extract_info=geometry;
247           Swap(image->columns,image->extract_info.width);
248           Swap(image->rows,image->extract_info.height);
249         }
250     }
251   image->compression=image_info->compression;
252   image->quality=image_info->quality;
253   image->endian=image_info->endian;
254   image->interlace=image_info->interlace;
255   image->units=image_info->units;
256   if (image_info->density != (char *) NULL)
257     {
258       GeometryInfo
259         geometry_info;
260 
261       flags=ParseGeometry(image_info->density,&geometry_info);
262       if ((flags & RhoValue) != 0)
263         image->resolution.x=geometry_info.rho;
264       image->resolution.y=image->resolution.x;
265       if ((flags & SigmaValue) != 0)
266         image->resolution.y=geometry_info.sigma;
267     }
268   if (image_info->page != (char *) NULL)
269     {
270       char
271         *geometry;
272 
273       image->page=image->extract_info;
274       geometry=GetPageGeometry(image_info->page);
275       (void) ParseAbsoluteGeometry(geometry,&image->page);
276       geometry=DestroyString(geometry);
277     }
278   if (image_info->depth != 0)
279     image->depth=image_info->depth;
280   image->dither=image_info->dither;
281   image->matte_color=image_info->matte_color;
282   image->background_color=image_info->background_color;
283   image->border_color=image_info->border_color;
284   image->transparent_color=image_info->transparent_color;
285   image->ping=image_info->ping;
286   image->progress_monitor=image_info->progress_monitor;
287   image->client_data=image_info->client_data;
288   if (image_info->cache != (void *) NULL)
289     ClonePixelCacheMethods(image->cache,image_info->cache);
290   /*
291     Set all global options that map to per-image settings.
292   */
293   (void) SyncImageSettings(image_info,image,exception);
294   /*
295     Global options that are only set for new images.
296   */
297   option=GetImageOption(image_info,"delay");
298   if (option != (const char *) NULL)
299     {
300       GeometryInfo
301         geometry_info;
302 
303       flags=ParseGeometry(option,&geometry_info);
304       if ((flags & GreaterValue) != 0)
305         {
306           if (image->delay > (size_t) floor(geometry_info.rho+0.5))
307             image->delay=(size_t) floor(geometry_info.rho+0.5);
308         }
309       else
310         if ((flags & LessValue) != 0)
311           {
312             if (image->delay < (size_t) floor(geometry_info.rho+0.5))
313               image->ticks_per_second=(ssize_t) floor(geometry_info.sigma+0.5);
314           }
315         else
316           image->delay=(size_t) floor(geometry_info.rho+0.5);
317       if ((flags & SigmaValue) != 0)
318         image->ticks_per_second=(ssize_t) floor(geometry_info.sigma+0.5);
319     }
320   option=GetImageOption(image_info,"dispose");
321   if (option != (const char *) NULL)
322     image->dispose=(DisposeType) ParseCommandOption(MagickDisposeOptions,
323       MagickFalse,option);
324   return(image);
325 }
326 
327 /*
328 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
329 %                                                                             %
330 %                                                                             %
331 %                                                                             %
332 %   A c q u i r e I m a g e I n f o                                           %
333 %                                                                             %
334 %                                                                             %
335 %                                                                             %
336 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
337 %
338 %  AcquireImageInfo() allocates the ImageInfo structure.
339 %
340 %  The format of the AcquireImageInfo method is:
341 %
342 %      ImageInfo *AcquireImageInfo(void)
343 %
344 */
AcquireImageInfo(void)345 MagickExport ImageInfo *AcquireImageInfo(void)
346 {
347   ImageInfo
348     *image_info;
349 
350   image_info=(ImageInfo *) AcquireCriticalMemory(sizeof(*image_info));
351   GetImageInfo(image_info);
352   return(image_info);
353 }
354 
355 /*
356 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
357 %                                                                             %
358 %                                                                             %
359 %                                                                             %
360 %   A c q u i r e N e x t I m a g e                                           %
361 %                                                                             %
362 %                                                                             %
363 %                                                                             %
364 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
365 %
366 %  AcquireNextImage() initializes the next image in a sequence to
367 %  default values.  The next member of image points to the newly allocated
368 %  image.  If there is a memory shortage, next is assigned NULL.
369 %
370 %  The format of the AcquireNextImage method is:
371 %
372 %      void AcquireNextImage(const ImageInfo *image_info,Image *image,
373 %        ExceptionInfo *exception)
374 %
375 %  A description of each parameter follows:
376 %
377 %    o image_info: Many of the image default values are set from this
378 %      structure.  For example, filename, compression, depth, background color,
379 %      and others.
380 %
381 %    o image: the image.
382 %
383 %    o exception: return any errors or warnings in this structure.
384 %
385 */
AcquireNextImage(const ImageInfo * image_info,Image * image,ExceptionInfo * exception)386 MagickExport void AcquireNextImage(const ImageInfo *image_info,Image *image,
387   ExceptionInfo *exception)
388 {
389   /*
390     Allocate image structure.
391   */
392   assert(image != (Image *) NULL);
393   assert(image->signature == MagickCoreSignature);
394   if (image->debug != MagickFalse)
395     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
396   image->next=AcquireImage(image_info,exception);
397   if (GetNextImageInList(image) == (Image *) NULL)
398     return;
399   (void) CopyMagickString(GetNextImageInList(image)->filename,image->filename,
400     MagickPathExtent);
401   if (image_info != (ImageInfo *) NULL)
402     (void) CopyMagickString(GetNextImageInList(image)->filename,
403       image_info->filename,MagickPathExtent);
404   DestroyBlob(GetNextImageInList(image));
405   image->next->blob=ReferenceBlob(image->blob);
406   image->next->endian=image->endian;
407   image->next->scene=image->scene+1;
408   image->next->previous=image;
409 }
410 
411 /*
412 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
413 %                                                                             %
414 %                                                                             %
415 %                                                                             %
416 %     A p p e n d I m a g e s                                                 %
417 %                                                                             %
418 %                                                                             %
419 %                                                                             %
420 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
421 %
422 %  AppendImages() takes all images from the current image pointer to the end
423 %  of the image list and appends them to each other top-to-bottom if the
424 %  stack parameter is true, otherwise left-to-right.
425 %
426 %  The current gravity setting effects how the image is justified in the
427 %  final image.
428 %
429 %  The format of the AppendImages method is:
430 %
431 %      Image *AppendImages(const Image *images,const MagickBooleanType stack,
432 %        ExceptionInfo *exception)
433 %
434 %  A description of each parameter follows:
435 %
436 %    o images: the image sequence.
437 %
438 %    o stack: A value other than 0 stacks the images top-to-bottom.
439 %
440 %    o exception: return any errors or warnings in this structure.
441 %
442 */
AppendImages(const Image * images,const MagickBooleanType stack,ExceptionInfo * exception)443 MagickExport Image *AppendImages(const Image *images,
444   const MagickBooleanType stack,ExceptionInfo *exception)
445 {
446 #define AppendImageTag  "Append/Image"
447 
448   CacheView
449     *append_view;
450 
451   Image
452     *append_image;
453 
454   MagickBooleanType
455     homogeneous_colorspace,
456     status;
457 
458   MagickOffsetType
459     n;
460 
461   PixelTrait
462     alpha_trait;
463 
464   RectangleInfo
465     geometry;
466 
467   register const Image
468     *next;
469 
470   size_t
471     depth,
472     height,
473     number_images,
474     width;
475 
476   ssize_t
477     x_offset,
478     y,
479     y_offset;
480 
481   /*
482     Compute maximum area of appended area.
483   */
484   assert(images != (Image *) NULL);
485   assert(images->signature == MagickCoreSignature);
486   if (images->debug != MagickFalse)
487     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
488   assert(exception != (ExceptionInfo *) NULL);
489   assert(exception->signature == MagickCoreSignature);
490   alpha_trait=images->alpha_trait;
491   number_images=1;
492   width=images->columns;
493   height=images->rows;
494   depth=images->depth;
495   homogeneous_colorspace=MagickTrue;
496   next=GetNextImageInList(images);
497   for ( ; next != (Image *) NULL; next=GetNextImageInList(next))
498   {
499     if (next->depth > depth)
500       depth=next->depth;
501     if (next->colorspace != images->colorspace)
502       homogeneous_colorspace=MagickFalse;
503     if (next->alpha_trait != UndefinedPixelTrait)
504       alpha_trait=BlendPixelTrait;
505     number_images++;
506     if (stack != MagickFalse)
507       {
508         if (next->columns > width)
509           width=next->columns;
510         height+=next->rows;
511         continue;
512       }
513     width+=next->columns;
514     if (next->rows > height)
515       height=next->rows;
516   }
517   /*
518     Append images.
519   */
520   append_image=CloneImage(images,width,height,MagickTrue,exception);
521   if (append_image == (Image *) NULL)
522     return((Image *) NULL);
523   if (SetImageStorageClass(append_image,DirectClass,exception) == MagickFalse)
524     {
525       append_image=DestroyImage(append_image);
526       return((Image *) NULL);
527     }
528   if (homogeneous_colorspace == MagickFalse)
529     (void) SetImageColorspace(append_image,sRGBColorspace,exception);
530   append_image->depth=depth;
531   append_image->alpha_trait=alpha_trait;
532   append_image->page=images->page;
533   (void) SetImageBackgroundColor(append_image,exception);
534   status=MagickTrue;
535   x_offset=0;
536   y_offset=0;
537   next=images;
538   append_view=AcquireAuthenticCacheView(append_image,exception);
539   for (n=0; n < (MagickOffsetType) number_images; n++)
540   {
541     CacheView
542       *image_view;
543 
544     MagickBooleanType
545       proceed;
546 
547     SetGeometry(append_image,&geometry);
548     GravityAdjustGeometry(next->columns,next->rows,next->gravity,&geometry);
549     if (stack != MagickFalse)
550       x_offset-=geometry.x;
551     else
552       y_offset-=geometry.y;
553     image_view=AcquireVirtualCacheView(next,exception);
554 #if defined(MAGICKCORE_OPENMP_SUPPORT)
555     #pragma omp parallel for schedule(static) shared(status) \
556       magick_number_threads(next,next,next->rows,1)
557 #endif
558     for (y=0; y < (ssize_t) next->rows; y++)
559     {
560       MagickBooleanType
561         sync;
562 
563       PixelInfo
564         pixel;
565 
566       register const Quantum
567         *magick_restrict p;
568 
569       register Quantum
570         *magick_restrict q;
571 
572       register ssize_t
573         x;
574 
575       if (status == MagickFalse)
576         continue;
577       p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
578       q=QueueCacheViewAuthenticPixels(append_view,x_offset,y+y_offset,
579         next->columns,1,exception);
580       if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
581         {
582           status=MagickFalse;
583           continue;
584         }
585       GetPixelInfo(next,&pixel);
586       for (x=0; x < (ssize_t) next->columns; x++)
587       {
588         GetPixelInfoPixel(next,p,&pixel);
589         SetPixelViaPixelInfo(append_image,&pixel,q);
590         p+=GetPixelChannels(next);
591         q+=GetPixelChannels(append_image);
592       }
593       sync=SyncCacheViewAuthenticPixels(append_view,exception);
594       if (sync == MagickFalse)
595         status=MagickFalse;
596     }
597     image_view=DestroyCacheView(image_view);
598     if (stack == MagickFalse)
599       {
600         x_offset+=(ssize_t) next->columns;
601         y_offset=0;
602       }
603     else
604       {
605         x_offset=0;
606         y_offset+=(ssize_t) next->rows;
607       }
608     proceed=SetImageProgress(append_image,AppendImageTag,n,number_images);
609     if (proceed == MagickFalse)
610       break;
611     next=GetNextImageInList(next);
612   }
613   append_view=DestroyCacheView(append_view);
614   if (status == MagickFalse)
615     append_image=DestroyImage(append_image);
616   return(append_image);
617 }
618 
619 /*
620 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
621 %                                                                             %
622 %                                                                             %
623 %                                                                             %
624 %   C a t c h I m a g e E x c e p t i o n                                     %
625 %                                                                             %
626 %                                                                             %
627 %                                                                             %
628 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
629 %
630 %  CatchImageException() returns if no exceptions are found in the image
631 %  sequence, otherwise it determines the most severe exception and reports
632 %  it as a warning or error depending on the severity.
633 %
634 %  The format of the CatchImageException method is:
635 %
636 %      ExceptionType CatchImageException(Image *image)
637 %
638 %  A description of each parameter follows:
639 %
640 %    o image: An image sequence.
641 %
642 */
CatchImageException(Image * image)643 MagickExport ExceptionType CatchImageException(Image *image)
644 {
645   ExceptionInfo
646     *exception;
647 
648   ExceptionType
649     severity;
650 
651   assert(image != (const Image *) NULL);
652   assert(image->signature == MagickCoreSignature);
653   if (image->debug != MagickFalse)
654     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
655   exception=AcquireExceptionInfo();
656   CatchException(exception);
657   severity=exception->severity;
658   exception=DestroyExceptionInfo(exception);
659   return(severity);
660 }
661 
662 /*
663 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
664 %                                                                             %
665 %                                                                             %
666 %                                                                             %
667 %   C l i p I m a g e P a t h                                                 %
668 %                                                                             %
669 %                                                                             %
670 %                                                                             %
671 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
672 %
673 %  ClipImagePath() sets the image clip mask based any clipping path information
674 %  if it exists.
675 %
676 %  The format of the ClipImagePath method is:
677 %
678 %      MagickBooleanType ClipImagePath(Image *image,const char *pathname,
679 %        const MagickBooleanType inside,ExceptionInfo *exception)
680 %
681 %  A description of each parameter follows:
682 %
683 %    o image: the image.
684 %
685 %    o pathname: name of clipping path resource. If name is preceded by #, use
686 %      clipping path numbered by name.
687 %
688 %    o inside: if non-zero, later operations take effect inside clipping path.
689 %      Otherwise later operations take effect outside clipping path.
690 %
691 %    o exception: return any errors or warnings in this structure.
692 %
693 */
694 
ClipImage(Image * image,ExceptionInfo * exception)695 MagickExport MagickBooleanType ClipImage(Image *image,ExceptionInfo *exception)
696 {
697   return(ClipImagePath(image,"#1",MagickTrue,exception));
698 }
699 
ClipImagePath(Image * image,const char * pathname,const MagickBooleanType inside,ExceptionInfo * exception)700 MagickExport MagickBooleanType ClipImagePath(Image *image,const char *pathname,
701   const MagickBooleanType inside,ExceptionInfo *exception)
702 {
703 #define ClipImagePathTag  "ClipPath/Image"
704 
705   char
706     *property;
707 
708   const char
709     *value;
710 
711   Image
712     *clip_mask;
713 
714   ImageInfo
715     *image_info;
716 
717   assert(image != (const Image *) NULL);
718   assert(image->signature == MagickCoreSignature);
719   if (image->debug != MagickFalse)
720     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
721   assert(pathname != NULL);
722   property=AcquireString(pathname);
723   (void) FormatLocaleString(property,MagickPathExtent,"8BIM:1999,2998:%s",
724     pathname);
725   value=GetImageProperty(image,property,exception);
726   property=DestroyString(property);
727   if (value == (const char *) NULL)
728     {
729       ThrowFileException(exception,OptionError,"NoClipPathDefined",
730         image->filename);
731       return(MagickFalse);
732     }
733   image_info=AcquireImageInfo();
734   (void) CopyMagickString(image_info->filename,image->filename,
735      MagickPathExtent);
736   (void) ConcatenateMagickString(image_info->filename,pathname,
737     MagickPathExtent);
738   clip_mask=BlobToImage(image_info,value,strlen(value),exception);
739   image_info=DestroyImageInfo(image_info);
740   if (clip_mask == (Image *) NULL)
741     return(MagickFalse);
742   if (clip_mask->storage_class == PseudoClass)
743     {
744       (void) SyncImage(clip_mask,exception);
745       if (SetImageStorageClass(clip_mask,DirectClass,exception) == MagickFalse)
746         return(MagickFalse);
747     }
748   if (inside == MagickFalse)
749     (void) NegateImage(clip_mask,MagickFalse,exception);
750   (void) FormatLocaleString(clip_mask->magick_filename,MagickPathExtent,
751     "8BIM:1999,2998:%s\nPS",pathname);
752   (void) SetImageMask(image,WritePixelMask,clip_mask,exception);
753   clip_mask=DestroyImage(clip_mask);
754   return(MagickTrue);
755 }
756 
757 /*
758 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
759 %                                                                             %
760 %                                                                             %
761 %                                                                             %
762 %   C l o n e I m a g e                                                       %
763 %                                                                             %
764 %                                                                             %
765 %                                                                             %
766 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
767 %
768 %  CloneImage() copies an image and returns the copy as a new image object.
769 %
770 %  If the specified columns and rows is 0, an exact copy of the image is
771 %  returned, otherwise the pixel data is undefined and must be initialized
772 %  with the QueueAuthenticPixels() and SyncAuthenticPixels() methods.  On
773 %  failure, a NULL image is returned and exception describes the reason for the
774 %  failure.
775 %
776 %  The format of the CloneImage method is:
777 %
778 %      Image *CloneImage(const Image *image,const size_t columns,
779 %        const size_t rows,const MagickBooleanType orphan,
780 %        ExceptionInfo *exception)
781 %
782 %  A description of each parameter follows:
783 %
784 %    o image: the image.
785 %
786 %    o columns: the number of columns in the cloned image.
787 %
788 %    o rows: the number of rows in the cloned image.
789 %
790 %    o detach:  With a value other than 0, the cloned image is detached from
791 %      its parent I/O stream.
792 %
793 %    o exception: return any errors or warnings in this structure.
794 %
795 */
CloneImage(const Image * image,const size_t columns,const size_t rows,const MagickBooleanType detach,ExceptionInfo * exception)796 MagickExport Image *CloneImage(const Image *image,const size_t columns,
797   const size_t rows,const MagickBooleanType detach,ExceptionInfo *exception)
798 {
799   Image
800     *clone_image;
801 
802   double
803     scale;
804 
805   size_t
806     length;
807 
808   /*
809     Clone the image.
810   */
811   assert(image != (const Image *) NULL);
812   assert(image->signature == MagickCoreSignature);
813   if (image->debug != MagickFalse)
814     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
815   assert(exception != (ExceptionInfo *) NULL);
816   assert(exception->signature == MagickCoreSignature);
817   if ((image->columns == 0) || (image->rows == 0))
818     {
819       (void) ThrowMagickException(exception,GetMagickModule(),CorruptImageError,
820         "NegativeOrZeroImageSize","`%s'",image->filename);
821       return((Image *) NULL);
822     }
823   clone_image=(Image *) AcquireCriticalMemory(sizeof(*clone_image));
824   (void) memset(clone_image,0,sizeof(*clone_image));
825   clone_image->signature=MagickCoreSignature;
826   clone_image->storage_class=image->storage_class;
827   clone_image->number_channels=image->number_channels;
828   clone_image->number_meta_channels=image->number_meta_channels;
829   clone_image->metacontent_extent=image->metacontent_extent;
830   clone_image->colorspace=image->colorspace;
831   clone_image->alpha_trait=image->alpha_trait;
832   clone_image->channels=image->channels;
833   clone_image->mask_trait=image->mask_trait;
834   clone_image->columns=image->columns;
835   clone_image->rows=image->rows;
836   clone_image->dither=image->dither;
837   clone_image->image_info=CloneImageInfo(image->image_info);
838   (void) CloneImageProfiles(clone_image,image);
839   (void) CloneImageProperties(clone_image,image);
840   (void) CloneImageArtifacts(clone_image,image);
841   GetTimerInfo(&clone_image->timer);
842   if (image->ascii85 != (void *) NULL)
843     Ascii85Initialize(clone_image);
844   clone_image->extent=image->extent;
845   clone_image->magick_columns=image->magick_columns;
846   clone_image->magick_rows=image->magick_rows;
847   clone_image->type=image->type;
848   clone_image->channel_mask=image->channel_mask;
849   clone_image->channel_map=ClonePixelChannelMap(image->channel_map);
850   (void) CopyMagickString(clone_image->magick_filename,image->magick_filename,
851     MagickPathExtent);
852   (void) CopyMagickString(clone_image->magick,image->magick,MagickPathExtent);
853   (void) CopyMagickString(clone_image->filename,image->filename,
854     MagickPathExtent);
855   clone_image->progress_monitor=image->progress_monitor;
856   clone_image->client_data=image->client_data;
857   clone_image->reference_count=1;
858   clone_image->next=image->next;
859   clone_image->previous=image->previous;
860   clone_image->list=NewImageList();
861   if (detach == MagickFalse)
862     clone_image->blob=ReferenceBlob(image->blob);
863   else
864     {
865       clone_image->next=NewImageList();
866       clone_image->previous=NewImageList();
867       clone_image->blob=CloneBlobInfo((BlobInfo *) NULL);
868     }
869   clone_image->ping=image->ping;
870   clone_image->debug=IsEventLogging();
871   clone_image->semaphore=AcquireSemaphoreInfo();
872   if (image->colormap != (PixelInfo *) NULL)
873     {
874       /*
875         Allocate and copy the image colormap.
876       */
877       clone_image->colors=image->colors;
878       length=(size_t) image->colors;
879       clone_image->colormap=(PixelInfo *) AcquireQuantumMemory(length+1,
880         sizeof(*clone_image->colormap));
881       if (clone_image->colormap == (PixelInfo *) NULL)
882         {
883           clone_image=DestroyImage(clone_image);
884           ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
885         }
886       (void) memcpy(clone_image->colormap,image->colormap,length*
887         sizeof(*clone_image->colormap));
888     }
889   if ((columns == 0) || (rows == 0))
890     {
891       if (image->montage != (char *) NULL)
892         (void) CloneString(&clone_image->montage,image->montage);
893       if (image->directory != (char *) NULL)
894         (void) CloneString(&clone_image->directory,image->directory);
895       clone_image->cache=ReferencePixelCache(image->cache);
896       return(clone_image);
897     }
898   scale=1.0;
899   if (image->columns != 0)
900     scale=(double) columns/(double) image->columns;
901   clone_image->page.width=(size_t) floor(scale*image->page.width+0.5);
902   clone_image->page.x=(ssize_t) ceil(scale*image->page.x-0.5);
903   clone_image->tile_offset.x=(ssize_t) ceil(scale*image->tile_offset.x-0.5);
904   scale=1.0;
905   if (image->rows != 0)
906     scale=(double) rows/(double) image->rows;
907   clone_image->page.height=(size_t) floor(scale*image->page.height+0.5);
908   clone_image->page.y=(ssize_t) ceil(scale*image->page.y-0.5);
909   clone_image->tile_offset.y=(ssize_t) ceil(scale*image->tile_offset.y-0.5);
910   clone_image->cache=ClonePixelCache(image->cache);
911   if (SetImageExtent(clone_image,columns,rows,exception) == MagickFalse)
912     clone_image=DestroyImage(clone_image);
913   return(clone_image);
914 }
915 
916 /*
917 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
918 %                                                                             %
919 %                                                                             %
920 %                                                                             %
921 %   C l o n e I m a g e I n f o                                               %
922 %                                                                             %
923 %                                                                             %
924 %                                                                             %
925 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
926 %
927 %  CloneImageInfo() makes a copy of the given image info structure.  If
928 %  NULL is specified, a new image info structure is created initialized to
929 %  default values.
930 %
931 %  The format of the CloneImageInfo method is:
932 %
933 %      ImageInfo *CloneImageInfo(const ImageInfo *image_info)
934 %
935 %  A description of each parameter follows:
936 %
937 %    o image_info: the image info.
938 %
939 */
CloneImageInfo(const ImageInfo * image_info)940 MagickExport ImageInfo *CloneImageInfo(const ImageInfo *image_info)
941 {
942   ImageInfo
943     *clone_info;
944 
945   clone_info=AcquireImageInfo();
946   if (image_info == (ImageInfo *) NULL)
947     return(clone_info);
948   clone_info->compression=image_info->compression;
949   clone_info->temporary=image_info->temporary;
950   clone_info->adjoin=image_info->adjoin;
951   clone_info->antialias=image_info->antialias;
952   clone_info->scene=image_info->scene;
953   clone_info->number_scenes=image_info->number_scenes;
954   clone_info->depth=image_info->depth;
955   if (image_info->size != (char *) NULL)
956     (void) CloneString(&clone_info->size,image_info->size);
957   if (image_info->extract != (char *) NULL)
958     (void) CloneString(&clone_info->extract,image_info->extract);
959   if (image_info->scenes != (char *) NULL)
960     (void) CloneString(&clone_info->scenes,image_info->scenes);
961   if (image_info->page != (char *) NULL)
962     (void) CloneString(&clone_info->page,image_info->page);
963   clone_info->interlace=image_info->interlace;
964   clone_info->endian=image_info->endian;
965   clone_info->units=image_info->units;
966   clone_info->quality=image_info->quality;
967   if (image_info->sampling_factor != (char *) NULL)
968     (void) CloneString(&clone_info->sampling_factor,
969       image_info->sampling_factor);
970   if (image_info->server_name != (char *) NULL)
971     (void) CloneString(&clone_info->server_name,image_info->server_name);
972   if (image_info->font != (char *) NULL)
973     (void) CloneString(&clone_info->font,image_info->font);
974   if (image_info->texture != (char *) NULL)
975     (void) CloneString(&clone_info->texture,image_info->texture);
976   if (image_info->density != (char *) NULL)
977     (void) CloneString(&clone_info->density,image_info->density);
978   clone_info->pointsize=image_info->pointsize;
979   clone_info->fuzz=image_info->fuzz;
980   clone_info->matte_color=image_info->matte_color;
981   clone_info->background_color=image_info->background_color;
982   clone_info->border_color=image_info->border_color;
983   clone_info->transparent_color=image_info->transparent_color;
984   clone_info->dither=image_info->dither;
985   clone_info->monochrome=image_info->monochrome;
986   clone_info->colorspace=image_info->colorspace;
987   clone_info->type=image_info->type;
988   clone_info->orientation=image_info->orientation;
989   clone_info->ping=image_info->ping;
990   clone_info->verbose=image_info->verbose;
991   clone_info->progress_monitor=image_info->progress_monitor;
992   clone_info->client_data=image_info->client_data;
993   clone_info->cache=image_info->cache;
994   if (image_info->cache != (void *) NULL)
995     clone_info->cache=ReferencePixelCache(image_info->cache);
996   if (image_info->profile != (void *) NULL)
997     clone_info->profile=(void *) CloneStringInfo((StringInfo *)
998       image_info->profile);
999   SetImageInfoFile(clone_info,image_info->file);
1000   SetImageInfoBlob(clone_info,image_info->blob,image_info->length);
1001   clone_info->stream=image_info->stream;
1002   clone_info->custom_stream=image_info->custom_stream;
1003   (void) CopyMagickString(clone_info->magick,image_info->magick,
1004     MagickPathExtent);
1005   (void) CopyMagickString(clone_info->unique,image_info->unique,
1006     MagickPathExtent);
1007   (void) CopyMagickString(clone_info->filename,image_info->filename,
1008     MagickPathExtent);
1009   clone_info->channel=image_info->channel;
1010   (void) CloneImageOptions(clone_info,image_info);
1011   clone_info->debug=IsEventLogging();
1012   clone_info->signature=image_info->signature;
1013   return(clone_info);
1014 }
1015 
1016 /*
1017 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1018 %                                                                             %
1019 %                                                                             %
1020 %                                                                             %
1021 %   C o p y I m a g e P i x e l s                                             %
1022 %                                                                             %
1023 %                                                                             %
1024 %                                                                             %
1025 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1026 %
1027 %  CopyImagePixels() copies pixels from the source image as defined by the
1028 %  geometry the destination image at the specified offset.
1029 %
1030 %  The format of the CopyImagePixels method is:
1031 %
1032 %      MagickBooleanType CopyImagePixels(Image *image,const Image *source_image,
1033 %        const RectangleInfo *geometry,const OffsetInfo *offset,
1034 %        ExceptionInfo *exception);
1035 %
1036 %  A description of each parameter follows:
1037 %
1038 %    o image: the destination image.
1039 %
1040 %    o source_image: the source image.
1041 %
1042 %    o geometry: define the dimensions of the source pixel rectangle.
1043 %
1044 %    o offset: define the offset in the destination image.
1045 %
1046 %    o exception: return any errors or warnings in this structure.
1047 %
1048 */
CopyImagePixels(Image * image,const Image * source_image,const RectangleInfo * geometry,const OffsetInfo * offset,ExceptionInfo * exception)1049 MagickExport MagickBooleanType CopyImagePixels(Image *image,
1050   const Image *source_image,const RectangleInfo *geometry,
1051   const OffsetInfo *offset,ExceptionInfo *exception)
1052 {
1053 #define CopyImageTag  "Copy/Image"
1054 
1055   CacheView
1056     *image_view,
1057     *source_view;
1058 
1059   MagickBooleanType
1060     status;
1061 
1062   MagickOffsetType
1063     progress;
1064 
1065   ssize_t
1066     y;
1067 
1068   assert(image != (Image *) NULL);
1069   if (image->debug != MagickFalse)
1070     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1071   assert(source_image != (Image *) NULL);
1072   assert(geometry != (RectangleInfo *) NULL);
1073   assert(offset != (OffsetInfo *) NULL);
1074   if ((offset->x < 0) || (offset->y < 0) ||
1075       ((ssize_t) (offset->x+geometry->width) > (ssize_t) image->columns) ||
1076       ((ssize_t) (offset->y+geometry->height) > (ssize_t) image->rows))
1077     ThrowBinaryException(OptionError,"GeometryDoesNotContainImage",
1078       image->filename);
1079   if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
1080     return(MagickFalse);
1081   /*
1082     Copy image pixels.
1083   */
1084   status=MagickTrue;
1085   progress=0;
1086   source_view=AcquireVirtualCacheView(source_image,exception);
1087   image_view=AcquireAuthenticCacheView(image,exception);
1088 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1089   #pragma omp parallel for schedule(static) shared(progress,status) \
1090     magick_number_threads(image,source_image,geometry->height,1)
1091 #endif
1092   for (y=0; y < (ssize_t) geometry->height; y++)
1093   {
1094     MagickBooleanType
1095       sync;
1096 
1097     register const Quantum
1098       *magick_restrict p;
1099 
1100     register ssize_t
1101       x;
1102 
1103     register Quantum
1104       *magick_restrict q;
1105 
1106     if (status == MagickFalse)
1107       continue;
1108     p=GetCacheViewVirtualPixels(source_view,geometry->x,y+geometry->y,
1109       geometry->width,1,exception);
1110     q=QueueCacheViewAuthenticPixels(image_view,offset->x,y+offset->y,
1111       geometry->width,1,exception);
1112     if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
1113       {
1114         status=MagickFalse;
1115         continue;
1116       }
1117     for (x=0; x < (ssize_t) geometry->width; x++)
1118     {
1119       register ssize_t
1120         i;
1121 
1122       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1123       {
1124         PixelChannel channel = GetPixelChannelChannel(image,i);
1125         PixelTrait traits = GetPixelChannelTraits(image,channel);
1126         PixelTrait source_traits=GetPixelChannelTraits(source_image,channel);
1127         if ((traits == UndefinedPixelTrait) ||
1128             ((traits & UpdatePixelTrait) == 0) ||
1129             (source_traits == UndefinedPixelTrait))
1130           continue;
1131         SetPixelChannel(image,channel,p[i],q);
1132       }
1133       p+=GetPixelChannels(source_image);
1134       q+=GetPixelChannels(image);
1135     }
1136     sync=SyncCacheViewAuthenticPixels(image_view,exception);
1137     if (sync == MagickFalse)
1138       status=MagickFalse;
1139     if (image->progress_monitor != (MagickProgressMonitor) NULL)
1140       {
1141         MagickBooleanType
1142           proceed;
1143 
1144 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1145         #pragma omp atomic
1146 #endif
1147         progress++;
1148         proceed=SetImageProgress(image,CopyImageTag,progress,image->rows);
1149         if (proceed == MagickFalse)
1150           status=MagickFalse;
1151       }
1152   }
1153   source_view=DestroyCacheView(source_view);
1154   image_view=DestroyCacheView(image_view);
1155   return(status);
1156 }
1157 
1158 /*
1159 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1160 %                                                                             %
1161 %                                                                             %
1162 %                                                                             %
1163 %   D e s t r o y I m a g e                                                   %
1164 %                                                                             %
1165 %                                                                             %
1166 %                                                                             %
1167 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1168 %
1169 %  DestroyImage() dereferences an image, deallocating memory associated with
1170 %  the image if the reference count becomes zero.
1171 %
1172 %  The format of the DestroyImage method is:
1173 %
1174 %      Image *DestroyImage(Image *image)
1175 %
1176 %  A description of each parameter follows:
1177 %
1178 %    o image: the image.
1179 %
1180 */
DestroyImage(Image * image)1181 MagickExport Image *DestroyImage(Image *image)
1182 {
1183   MagickBooleanType
1184     destroy;
1185 
1186   /*
1187     Dereference image.
1188   */
1189   assert(image != (Image *) NULL);
1190   assert(image->signature == MagickCoreSignature);
1191   if (image->debug != MagickFalse)
1192     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1193   destroy=MagickFalse;
1194   LockSemaphoreInfo(image->semaphore);
1195   image->reference_count--;
1196   if (image->reference_count == 0)
1197     destroy=MagickTrue;
1198   UnlockSemaphoreInfo(image->semaphore);
1199   if (destroy == MagickFalse)
1200     return((Image *) NULL);
1201   /*
1202     Destroy image.
1203   */
1204   DestroyImagePixels(image);
1205   image->channel_map=DestroyPixelChannelMap(image->channel_map);
1206   if (image->montage != (char *) NULL)
1207     image->montage=DestroyString(image->montage);
1208   if (image->directory != (char *) NULL)
1209     image->directory=DestroyString(image->directory);
1210   if (image->colormap != (PixelInfo *) NULL)
1211     image->colormap=(PixelInfo *) RelinquishMagickMemory(image->colormap);
1212   if (image->geometry != (char *) NULL)
1213     image->geometry=DestroyString(image->geometry);
1214   DestroyImageProfiles(image);
1215   DestroyImageProperties(image);
1216   DestroyImageArtifacts(image);
1217   if (image->ascii85 != (Ascii85Info *) NULL)
1218     image->ascii85=(Ascii85Info *) RelinquishMagickMemory(image->ascii85);
1219   if (image->image_info != (ImageInfo *) NULL)
1220     image->image_info=DestroyImageInfo(image->image_info);
1221   DestroyBlob(image);
1222   if (image->semaphore != (SemaphoreInfo *) NULL)
1223     RelinquishSemaphoreInfo(&image->semaphore);
1224   image->signature=(~MagickCoreSignature);
1225   image=(Image *) RelinquishMagickMemory(image);
1226   return(image);
1227 }
1228 
1229 /*
1230 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1231 %                                                                             %
1232 %                                                                             %
1233 %                                                                             %
1234 %   D e s t r o y I m a g e I n f o                                           %
1235 %                                                                             %
1236 %                                                                             %
1237 %                                                                             %
1238 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1239 %
1240 %  DestroyImageInfo() deallocates memory associated with an ImageInfo
1241 %  structure.
1242 %
1243 %  The format of the DestroyImageInfo method is:
1244 %
1245 %      ImageInfo *DestroyImageInfo(ImageInfo *image_info)
1246 %
1247 %  A description of each parameter follows:
1248 %
1249 %    o image_info: the image info.
1250 %
1251 */
DestroyImageInfo(ImageInfo * image_info)1252 MagickExport ImageInfo *DestroyImageInfo(ImageInfo *image_info)
1253 {
1254   assert(image_info != (ImageInfo *) NULL);
1255   assert(image_info->signature == MagickCoreSignature);
1256   if (image_info->debug != MagickFalse)
1257     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1258       image_info->filename);
1259   if (image_info->size != (char *) NULL)
1260     image_info->size=DestroyString(image_info->size);
1261   if (image_info->extract != (char *) NULL)
1262     image_info->extract=DestroyString(image_info->extract);
1263   if (image_info->scenes != (char *) NULL)
1264     image_info->scenes=DestroyString(image_info->scenes);
1265   if (image_info->page != (char *) NULL)
1266     image_info->page=DestroyString(image_info->page);
1267   if (image_info->sampling_factor != (char *) NULL)
1268     image_info->sampling_factor=DestroyString(
1269       image_info->sampling_factor);
1270   if (image_info->server_name != (char *) NULL)
1271     image_info->server_name=DestroyString(
1272       image_info->server_name);
1273   if (image_info->font != (char *) NULL)
1274     image_info->font=DestroyString(image_info->font);
1275   if (image_info->texture != (char *) NULL)
1276     image_info->texture=DestroyString(image_info->texture);
1277   if (image_info->density != (char *) NULL)
1278     image_info->density=DestroyString(image_info->density);
1279   if (image_info->cache != (void *) NULL)
1280     image_info->cache=DestroyPixelCache(image_info->cache);
1281   if (image_info->profile != (StringInfo *) NULL)
1282     image_info->profile=(void *) DestroyStringInfo((StringInfo *)
1283       image_info->profile);
1284   DestroyImageOptions(image_info);
1285   image_info->signature=(~MagickCoreSignature);
1286   image_info=(ImageInfo *) RelinquishMagickMemory(image_info);
1287   return(image_info);
1288 }
1289 
1290 /*
1291 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1292 %                                                                             %
1293 %                                                                             %
1294 %                                                                             %
1295 +   D i s a s s o c i a t e I m a g e S t r e a m                             %
1296 %                                                                             %
1297 %                                                                             %
1298 %                                                                             %
1299 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1300 %
1301 %  DisassociateImageStream() disassociates the image stream.  It checks if the
1302 %  blob of the specified image is referenced by other images. If the reference
1303 %  count is higher then 1 a new blob is assigned to the specified image.
1304 %
1305 %  The format of the DisassociateImageStream method is:
1306 %
1307 %      void DisassociateImageStream(const Image *image)
1308 %
1309 %  A description of each parameter follows:
1310 %
1311 %    o image: the image.
1312 %
1313 */
DisassociateImageStream(Image * image)1314 MagickExport void DisassociateImageStream(Image *image)
1315 {
1316   assert(image != (Image *) NULL);
1317   assert(image->signature == MagickCoreSignature);
1318   if (image->debug != MagickFalse)
1319     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1320   DisassociateBlob(image);
1321 }
1322 
1323 /*
1324 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1325 %                                                                             %
1326 %                                                                             %
1327 %                                                                             %
1328 %   G e t I m a g e I n f o                                                   %
1329 %                                                                             %
1330 %                                                                             %
1331 %                                                                             %
1332 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1333 %
1334 %  GetImageInfo() initializes image_info to default values.
1335 %
1336 %  The format of the GetImageInfo method is:
1337 %
1338 %      void GetImageInfo(ImageInfo *image_info)
1339 %
1340 %  A description of each parameter follows:
1341 %
1342 %    o image_info: the image info.
1343 %
1344 */
GetImageInfo(ImageInfo * image_info)1345 MagickExport void GetImageInfo(ImageInfo *image_info)
1346 {
1347   char
1348     *synchronize;
1349 
1350   ExceptionInfo
1351     *exception;
1352 
1353   /*
1354     File and image dimension members.
1355   */
1356   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1357   assert(image_info != (ImageInfo *) NULL);
1358   (void) memset(image_info,0,sizeof(*image_info));
1359   image_info->adjoin=MagickTrue;
1360   image_info->interlace=NoInterlace;
1361   image_info->channel=DefaultChannels;
1362   image_info->quality=UndefinedCompressionQuality;
1363   image_info->antialias=MagickTrue;
1364   image_info->dither=MagickTrue;
1365   synchronize=GetEnvironmentValue("MAGICK_SYNCHRONIZE");
1366   if (synchronize != (const char *) NULL)
1367     {
1368       image_info->synchronize=IsStringTrue(synchronize);
1369       synchronize=DestroyString(synchronize);
1370     }
1371   exception=AcquireExceptionInfo();
1372   (void) QueryColorCompliance(BackgroundColor,AllCompliance,
1373     &image_info->background_color,exception);
1374   (void) QueryColorCompliance(BorderColor,AllCompliance,
1375     &image_info->border_color,exception);
1376   (void) QueryColorCompliance(MatteColor,AllCompliance,&image_info->matte_color,
1377     exception);
1378   (void) QueryColorCompliance(TransparentColor,AllCompliance,
1379     &image_info->transparent_color,exception);
1380   exception=DestroyExceptionInfo(exception);
1381   image_info->debug=IsEventLogging();
1382   image_info->signature=MagickCoreSignature;
1383 }
1384 
1385 /*
1386 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1387 %                                                                             %
1388 %                                                                             %
1389 %                                                                             %
1390 %   G e t I m a g e I n f o F i l e                                           %
1391 %                                                                             %
1392 %                                                                             %
1393 %                                                                             %
1394 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1395 %
1396 %  GetImageInfoFile() returns the image info file member.
1397 %
1398 %  The format of the GetImageInfoFile method is:
1399 %
1400 %      FILE *GetImageInfoFile(const ImageInfo *image_info)
1401 %
1402 %  A description of each parameter follows:
1403 %
1404 %    o image_info: the image info.
1405 %
1406 */
GetImageInfoFile(const ImageInfo * image_info)1407 MagickExport FILE *GetImageInfoFile(const ImageInfo *image_info)
1408 {
1409   return(image_info->file);
1410 }
1411 
1412 /*
1413 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1414 %                                                                             %
1415 %                                                                             %
1416 %                                                                             %
1417 %   G e t I m a g e M a s k                                                   %
1418 %                                                                             %
1419 %                                                                             %
1420 %                                                                             %
1421 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1422 %
1423 %  GetImageMask() returns the mask associated with the image.
1424 %
1425 %  The format of the GetImageMask method is:
1426 %
1427 %      Image *GetImageMask(const Image *image,const PixelMask type,
1428 %        ExceptionInfo *exception)
1429 %
1430 %  A description of each parameter follows:
1431 %
1432 %    o image: the image.
1433 %
1434 %    o type: the mask type, ReadPixelMask or WritePixelMask.
1435 %
1436 */
GetImageMask(const Image * image,const PixelMask type,ExceptionInfo * exception)1437 MagickExport Image *GetImageMask(const Image *image,const PixelMask type,
1438   ExceptionInfo *exception)
1439 {
1440   CacheView
1441     *mask_view,
1442     *image_view;
1443 
1444   Image
1445     *mask_image;
1446 
1447   MagickBooleanType
1448     status;
1449 
1450   ssize_t
1451     y;
1452 
1453   /*
1454     Get image mask.
1455   */
1456   assert(image != (Image *) NULL);
1457   if (image->debug != MagickFalse)
1458     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1459   assert(image->signature == MagickCoreSignature);
1460   switch (type)
1461   {
1462     case ReadPixelMask:
1463     {
1464       if ((image->channels & ReadMaskChannel) == 0)
1465         return((Image *) NULL);
1466       break;
1467     }
1468     case WritePixelMask:
1469     {
1470       if ((image->channels & WriteMaskChannel) == 0)
1471         return((Image *) NULL);
1472       break;
1473     }
1474     default:
1475     {
1476       if ((image->channels & CompositeMaskChannel) == 0)
1477         return((Image *) NULL);
1478       break;
1479     }
1480   }
1481   mask_image=AcquireImage((ImageInfo *) NULL,exception);
1482   status=SetImageExtent(mask_image,image->columns,image->rows,exception);
1483   if (status == MagickFalse)
1484     return(DestroyImage(mask_image));
1485   status=MagickTrue;
1486   mask_image->alpha_trait=UndefinedPixelTrait;
1487   (void) SetImageColorspace(mask_image,GRAYColorspace,exception);
1488   image_view=AcquireVirtualCacheView(image,exception);
1489   mask_view=AcquireAuthenticCacheView(mask_image,exception);
1490   for (y=0; y < (ssize_t) image->rows; y++)
1491   {
1492     register const Quantum
1493       *magick_restrict p;
1494 
1495     register Quantum
1496       *magick_restrict q;
1497 
1498     register ssize_t
1499       x;
1500 
1501     if (status == MagickFalse)
1502       continue;
1503     p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1504     q=GetCacheViewAuthenticPixels(mask_view,0,y,mask_image->columns,1,
1505       exception);
1506     if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
1507       {
1508         status=MagickFalse;
1509         continue;
1510       }
1511     for (x=0; x < (ssize_t) image->columns; x++)
1512     {
1513       switch (type)
1514       {
1515         case ReadPixelMask:
1516         {
1517           SetPixelGray(mask_image,GetPixelReadMask(image,p),q);
1518           break;
1519         }
1520         case WritePixelMask:
1521         {
1522           SetPixelGray(mask_image,GetPixelWriteMask(image,p),q);
1523           break;
1524         }
1525         default:
1526         {
1527           SetPixelGray(mask_image,GetPixelCompositeMask(image,p),q);
1528           break;
1529         }
1530       }
1531       p+=GetPixelChannels(image);
1532       q+=GetPixelChannels(mask_image);
1533     }
1534     if (SyncCacheViewAuthenticPixels(mask_view,exception) == MagickFalse)
1535       status=MagickFalse;
1536   }
1537   mask_view=DestroyCacheView(mask_view);
1538   image_view=DestroyCacheView(image_view);
1539   if (status == MagickFalse)
1540     mask_image=DestroyImage(mask_image);
1541   return(mask_image);
1542 }
1543 
1544 /*
1545 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1546 %                                                                             %
1547 %                                                                             %
1548 %                                                                             %
1549 +   G e t I m a g e R e f e r e n c e C o u n t                               %
1550 %                                                                             %
1551 %                                                                             %
1552 %                                                                             %
1553 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1554 %
1555 %  GetImageReferenceCount() returns the image reference count.
1556 %
1557 %  The format of the GetReferenceCount method is:
1558 %
1559 %      ssize_t GetImageReferenceCount(Image *image)
1560 %
1561 %  A description of each parameter follows:
1562 %
1563 %    o image: the image.
1564 %
1565 */
GetImageReferenceCount(Image * image)1566 MagickExport ssize_t GetImageReferenceCount(Image *image)
1567 {
1568   ssize_t
1569     reference_count;
1570 
1571   assert(image != (Image *) NULL);
1572   assert(image->signature == MagickCoreSignature);
1573   if (image->debug != MagickFalse)
1574     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1575   LockSemaphoreInfo(image->semaphore);
1576   reference_count=image->reference_count;
1577   UnlockSemaphoreInfo(image->semaphore);
1578   return(reference_count);
1579 }
1580 
1581 /*
1582 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1583 %                                                                             %
1584 %                                                                             %
1585 %                                                                             %
1586 %   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                       %
1587 %                                                                             %
1588 %                                                                             %
1589 %                                                                             %
1590 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1591 %
1592 %  GetImageVirtualPixelMethod() gets the "virtual pixels" method for the
1593 %  image.  A virtual pixel is any pixel access that is outside the boundaries
1594 %  of the image cache.
1595 %
1596 %  The format of the GetImageVirtualPixelMethod() method is:
1597 %
1598 %      VirtualPixelMethod GetImageVirtualPixelMethod(const Image *image)
1599 %
1600 %  A description of each parameter follows:
1601 %
1602 %    o image: the image.
1603 %
1604 */
GetImageVirtualPixelMethod(const Image * image)1605 MagickExport VirtualPixelMethod GetImageVirtualPixelMethod(const Image *image)
1606 {
1607   assert(image != (Image *) NULL);
1608   assert(image->signature == MagickCoreSignature);
1609   if (image->debug != MagickFalse)
1610     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1611   return(GetPixelCacheVirtualMethod(image));
1612 }
1613 
1614 /*
1615 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1616 %                                                                             %
1617 %                                                                             %
1618 %                                                                             %
1619 %  I n t e r p r e t I m a g e F i l e n a m e                                %
1620 %                                                                             %
1621 %                                                                             %
1622 %                                                                             %
1623 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1624 %
1625 %  InterpretImageFilename() interprets embedded characters in an image filename.
1626 %  The filename length is returned.
1627 %
1628 %  The format of the InterpretImageFilename method is:
1629 %
1630 %      size_t InterpretImageFilename(const ImageInfo *image_info,Image *image,
1631 %        const char *format,int value,char *filename,ExceptionInfo *exception)
1632 %
1633 %  A description of each parameter follows.
1634 %
1635 %    o image_info: the image info..
1636 %
1637 %    o image: the image.
1638 %
1639 %    o format:  A filename describing the format to use to write the numeric
1640 %      argument. Only the first numeric format identifier is replaced.
1641 %
1642 %    o value:  Numeric value to substitute into format filename.
1643 %
1644 %    o filename:  return the formatted filename in this character buffer.
1645 %
1646 %    o exception: return any errors or warnings in this structure.
1647 %
1648 */
InterpretImageFilename(const ImageInfo * image_info,Image * image,const char * format,int value,char * filename,ExceptionInfo * exception)1649 MagickExport size_t InterpretImageFilename(const ImageInfo *image_info,
1650   Image *image,const char *format,int value,char *filename,
1651   ExceptionInfo *exception)
1652 {
1653   char
1654     *q;
1655 
1656   int
1657     c;
1658 
1659   MagickBooleanType
1660     canonical;
1661 
1662   register const char
1663     *p;
1664 
1665   ssize_t
1666     field_width,
1667     offset;
1668 
1669   canonical=MagickFalse;
1670   offset=0;
1671   (void) CopyMagickString(filename,format,MagickPathExtent);
1672   for (p=strchr(format,'%'); p != (char *) NULL; p=strchr(p+1,'%'))
1673   {
1674     q=(char *) p+1;
1675     if (*q == '%')
1676       {
1677         p=q+1;
1678         continue;
1679       }
1680     field_width=0;
1681     if (*q == '0')
1682       field_width=(ssize_t) strtol(q,&q,10);
1683     switch (*q)
1684     {
1685       case 'd':
1686       case 'o':
1687       case 'x':
1688       {
1689         q++;
1690         c=(*q);
1691         *q='\0';
1692         (void) FormatLocaleString(filename+(p-format-offset),(size_t)
1693           (MagickPathExtent-(p-format-offset)),p,value);
1694         offset+=(4-field_width);
1695         *q=c;
1696         (void) ConcatenateMagickString(filename,q,MagickPathExtent);
1697         canonical=MagickTrue;
1698         if (*(q-1) != '%')
1699           break;
1700         p++;
1701         break;
1702       }
1703       case '[':
1704       {
1705         char
1706           pattern[MagickPathExtent];
1707 
1708         const char
1709           *option;
1710 
1711         register char
1712           *r;
1713 
1714         register ssize_t
1715           i;
1716 
1717         ssize_t
1718           depth;
1719 
1720         /*
1721           Image option.
1722         */
1723         if (strchr(p,']') == (char *) NULL)
1724           break;
1725         depth=1;
1726         r=q+1;
1727         for (i=0; (i < (MagickPathExtent-1L)) && (*r != '\0'); i++)
1728         {
1729           if (*r == '[')
1730             depth++;
1731           if (*r == ']')
1732             depth--;
1733           if (depth <= 0)
1734             break;
1735           pattern[i]=(*r++);
1736         }
1737         pattern[i]='\0';
1738         if (LocaleNCompare(pattern,"filename:",9) != 0)
1739           break;
1740         option=(const char *) NULL;
1741         if (image != (Image *) NULL)
1742           option=GetImageProperty(image,pattern,exception);
1743         if ((option == (const char *) NULL) && (image != (Image *) NULL))
1744           option=GetImageArtifact(image,pattern);
1745         if ((option == (const char *) NULL) &&
1746             (image_info != (ImageInfo *) NULL))
1747           option=GetImageOption(image_info,pattern);
1748         if (option == (const char *) NULL)
1749           break;
1750         q--;
1751         c=(*q);
1752         *q='\0';
1753         (void) CopyMagickString(filename+(p-format-offset),option,(size_t)
1754           (MagickPathExtent-(p-format-offset)));
1755         offset+=strlen(pattern)-strlen(option)+3;
1756         *q=c;
1757         (void) ConcatenateMagickString(filename,r+1,MagickPathExtent);
1758         canonical=MagickTrue;
1759         if (*(q-1) != '%')
1760           break;
1761         p++;
1762         break;
1763       }
1764       default:
1765         break;
1766     }
1767   }
1768   if (canonical == MagickFalse)
1769     (void) CopyMagickString(filename,format,MagickPathExtent);
1770   else
1771     for (q=filename; *q != '\0'; q++)
1772       if ((*q == '%') && (*(q+1) == '%'))
1773         (void) CopyMagickString(q,q+1,(size_t) (MagickPathExtent-(q-filename)));
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_trait != UndefinedPixelTrait) &&
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)
2665     {
2666       image->depth=8;
2667       (void) ThrowMagickException(exception,GetMagickModule(),ImageError,
2668         "ImageDepthNotSupported","`%s'",image->filename);
2669     }
2670   if (image->depth > (8*sizeof(MagickSizeType)))
2671     {
2672       image->depth=8*sizeof(MagickSizeType);
2673       (void) ThrowMagickException(exception,GetMagickModule(),ImageError,
2674         "ImageDepthNotSupported","`%s'",image->filename);
2675     }
2676   return(SyncImagePixelCache(image,exception));
2677 }
2678 
2679 /*
2680 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2681 %                                                                             %
2682 %                                                                             %
2683 %                                                                             %
2684 +   S e t I m a g e I n f o                                                   %
2685 %                                                                             %
2686 %                                                                             %
2687 %                                                                             %
2688 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2689 %
2690 %  SetImageInfo() initializes the 'magick' field of the ImageInfo structure.
2691 %  It is set to a type of image format based on the prefix or suffix of the
2692 %  filename.  For example, 'ps:image' returns PS indicating a Postscript image.
2693 %  JPEG is returned for this filename: 'image.jpg'.  The filename prefix has
2694 %  precendence over the suffix.  Use an optional index enclosed in brackets
2695 %  after a file name to specify a desired scene of a multi-resolution image
2696 %  format like Photo CD (e.g. img0001.pcd[4]).  A True (non-zero) return value
2697 %  indicates success.
2698 %
2699 %  The format of the SetImageInfo method is:
2700 %
2701 %      MagickBooleanType SetImageInfo(ImageInfo *image_info,
2702 %        const unsigned int frames,ExceptionInfo *exception)
2703 %
2704 %  A description of each parameter follows:
2705 %
2706 %    o image_info: the image info.
2707 %
2708 %    o frames: the number of images you intend to write.
2709 %
2710 %    o exception: return any errors or warnings in this structure.
2711 %
2712 */
SetImageInfo(ImageInfo * image_info,const unsigned int frames,ExceptionInfo * exception)2713 MagickExport MagickBooleanType SetImageInfo(ImageInfo *image_info,
2714   const unsigned int frames,ExceptionInfo *exception)
2715 {
2716   char
2717     component[MagickPathExtent],
2718     magic[MagickPathExtent],
2719 #if defined(MAGICKCORE_ZLIB_DELEGATE) || defined(MAGICKCORE_BZLIB_DELEGATE)
2720     path[MagickPathExtent],
2721 #endif
2722     *q;
2723 
2724   const MagicInfo
2725     *magic_info;
2726 
2727   const MagickInfo
2728     *magick_info;
2729 
2730   ExceptionInfo
2731     *sans_exception;
2732 
2733   Image
2734     *image;
2735 
2736   MagickBooleanType
2737     status;
2738 
2739   register const char
2740     *p;
2741 
2742   ssize_t
2743     count;
2744 
2745   /*
2746     Look for 'image.format' in filename.
2747   */
2748   assert(image_info != (ImageInfo *) NULL);
2749   assert(image_info->signature == MagickCoreSignature);
2750   if (image_info->debug != MagickFalse)
2751     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2752       image_info->filename);
2753   *component='\0';
2754   GetPathComponent(image_info->filename,SubimagePath,component);
2755   if (*component != '\0')
2756     {
2757       /*
2758         Look for scene specification (e.g. img0001.pcd[4]).
2759       */
2760       if (IsSceneGeometry(component,MagickFalse) == MagickFalse)
2761         {
2762           if (IsGeometry(component) != MagickFalse)
2763             (void) CloneString(&image_info->extract,component);
2764         }
2765       else
2766         {
2767           size_t
2768             first,
2769             last;
2770 
2771           (void) CloneString(&image_info->scenes,component);
2772           image_info->scene=StringToUnsignedLong(image_info->scenes);
2773           image_info->number_scenes=image_info->scene;
2774           p=image_info->scenes;
2775           for (q=(char *) image_info->scenes; *q != '\0'; p++)
2776           {
2777             while ((isspace((int) ((unsigned char) *p)) != 0) || (*p == ','))
2778               p++;
2779             first=(size_t) strtol(p,&q,10);
2780             last=first;
2781             while (isspace((int) ((unsigned char) *q)) != 0)
2782               q++;
2783             if (*q == '-')
2784               last=(size_t) strtol(q+1,&q,10);
2785             if (first > last)
2786               Swap(first,last);
2787             if (first < image_info->scene)
2788               image_info->scene=first;
2789             if (last > image_info->number_scenes)
2790               image_info->number_scenes=last;
2791             p=q;
2792           }
2793           image_info->number_scenes-=image_info->scene-1;
2794         }
2795     }
2796   *component='\0';
2797   if (*image_info->magick == '\0')
2798     GetPathComponent(image_info->filename,ExtensionPath,component);
2799 #if defined(MAGICKCORE_ZLIB_DELEGATE)
2800   if (*component != '\0')
2801     if ((LocaleCompare(component,"gz") == 0) ||
2802         (LocaleCompare(component,"Z") == 0) ||
2803         (LocaleCompare(component,"svgz") == 0) ||
2804         (LocaleCompare(component,"wmz") == 0))
2805       {
2806         (void) CopyMagickString(path,image_info->filename,MagickPathExtent);
2807         path[strlen(path)-strlen(component)-1]='\0';
2808         GetPathComponent(path,ExtensionPath,component);
2809       }
2810 #endif
2811 #if defined(MAGICKCORE_BZLIB_DELEGATE)
2812   if (*component != '\0')
2813     if (LocaleCompare(component,"bz2") == 0)
2814       {
2815         (void) CopyMagickString(path,image_info->filename,MagickPathExtent);
2816         path[strlen(path)-strlen(component)-1]='\0';
2817         GetPathComponent(path,ExtensionPath,component);
2818       }
2819 #endif
2820   image_info->affirm=MagickFalse;
2821   sans_exception=AcquireExceptionInfo();
2822   if ((*component != '\0') && (IsGlob(component) == MagickFalse))
2823     {
2824       MagickFormatType
2825         format_type;
2826 
2827       register ssize_t
2828         i;
2829 
2830       static const char
2831         *format_type_formats[] =
2832         {
2833           "AUTOTRACE",
2834           "BROWSE",
2835           "DCRAW",
2836           "EDIT",
2837           "LAUNCH",
2838           "MPEG:DECODE",
2839           "MPEG:ENCODE",
2840           "PRINT",
2841           "PS:ALPHA",
2842           "PS:CMYK",
2843           "PS:COLOR",
2844           "PS:GRAY",
2845           "PS:MONO",
2846           "SCAN",
2847           "SHOW",
2848           "WIN",
2849           (char *) NULL
2850         };
2851 
2852       /*
2853         User specified image format.
2854       */
2855       (void) CopyMagickString(magic,component,MagickPathExtent);
2856       LocaleUpper(magic);
2857       /*
2858         Look for explicit image formats.
2859       */
2860       format_type=UndefinedFormatType;
2861       magick_info=GetMagickInfo(magic,sans_exception);
2862       if ((magick_info != (const MagickInfo *) NULL) &&
2863           (magick_info->format_type != UndefinedFormatType))
2864         format_type=magick_info->format_type;
2865       i=0;
2866       while ((format_type == UndefinedFormatType) &&
2867              (format_type_formats[i] != (char *) NULL))
2868       {
2869         if ((*magic == *format_type_formats[i]) &&
2870             (LocaleCompare(magic,format_type_formats[i]) == 0))
2871           format_type=ExplicitFormatType;
2872         i++;
2873       }
2874       if (format_type == UndefinedFormatType)
2875         (void) CopyMagickString(image_info->magick,magic,MagickPathExtent);
2876       else
2877         if (format_type == ExplicitFormatType)
2878           {
2879             image_info->affirm=MagickTrue;
2880             (void) CopyMagickString(image_info->magick,magic,MagickPathExtent);
2881           }
2882       if (LocaleCompare(magic,"RGB") == 0)
2883         image_info->affirm=MagickFalse;  /* maybe SGI disguised as RGB */
2884     }
2885   /*
2886     Look for explicit 'format:image' in filename.
2887   */
2888   *magic='\0';
2889   GetPathComponent(image_info->filename,MagickPath,magic);
2890   if (*magic == '\0')
2891     {
2892       (void) CopyMagickString(magic,image_info->magick,MagickPathExtent);
2893       magick_info=GetMagickInfo(magic,sans_exception);
2894       if (frames == 0)
2895         GetPathComponent(image_info->filename,CanonicalPath,component);
2896       else
2897         GetPathComponent(image_info->filename,SubcanonicalPath,component);
2898       (void) CopyMagickString(image_info->filename,component,MagickPathExtent);
2899     }
2900   else
2901     {
2902       const DelegateInfo
2903         *delegate_info;
2904 
2905       /*
2906         User specified image format.
2907       */
2908       LocaleUpper(magic);
2909       magick_info=GetMagickInfo(magic,sans_exception);
2910       delegate_info=GetDelegateInfo(magic,"*",sans_exception);
2911       if (delegate_info == (const DelegateInfo *) NULL)
2912         delegate_info=GetDelegateInfo("*",magic,sans_exception);
2913       if (((magick_info != (const MagickInfo *) NULL) ||
2914            (delegate_info != (const DelegateInfo *) NULL)) &&
2915           (IsMagickConflict(magic) == MagickFalse))
2916         {
2917           image_info->affirm=MagickTrue;
2918           (void) CopyMagickString(image_info->magick,magic,MagickPathExtent);
2919           GetPathComponent(image_info->filename,CanonicalPath,component);
2920           (void) CopyMagickString(image_info->filename,component,
2921             MagickPathExtent);
2922         }
2923     }
2924   sans_exception=DestroyExceptionInfo(sans_exception);
2925   if ((magick_info == (const MagickInfo *) NULL) ||
2926       (GetMagickEndianSupport(magick_info) == MagickFalse))
2927     image_info->endian=UndefinedEndian;
2928   if ((image_info->adjoin != MagickFalse) && (frames > 1))
2929     {
2930       /*
2931         Test for multiple image support (e.g. image%02d.png).
2932       */
2933       (void) InterpretImageFilename(image_info,(Image *) NULL,
2934         image_info->filename,(int) image_info->scene,component,exception);
2935       if ((LocaleCompare(component,image_info->filename) != 0) &&
2936           (strchr(component,'%') == (char *) NULL))
2937         image_info->adjoin=MagickFalse;
2938     }
2939   if ((image_info->adjoin != MagickFalse) && (frames > 0))
2940     {
2941       /*
2942         Some image formats do not support multiple frames per file.
2943       */
2944       magick_info=GetMagickInfo(magic,exception);
2945       if (magick_info != (const MagickInfo *) NULL)
2946         if (GetMagickAdjoin(magick_info) == MagickFalse)
2947           image_info->adjoin=MagickFalse;
2948     }
2949   if (image_info->affirm != MagickFalse)
2950     return(MagickTrue);
2951   if (frames == 0)
2952     {
2953       unsigned char
2954         *magick;
2955 
2956       size_t
2957         magick_size;
2958 
2959       /*
2960         Determine the image format from the first few bytes of the file.
2961       */
2962       magick_size=GetMagicPatternExtent(exception);
2963       if (magick_size == 0)
2964         return(MagickFalse);
2965       image=AcquireImage(image_info,exception);
2966       (void) CopyMagickString(image->filename,image_info->filename,
2967         MagickPathExtent);
2968       status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
2969       if (status == MagickFalse)
2970         {
2971           image=DestroyImage(image);
2972           return(MagickFalse);
2973         }
2974       if ((IsBlobSeekable(image) == MagickFalse) ||
2975           (IsBlobExempt(image) != MagickFalse))
2976         {
2977           /*
2978             Copy image to seekable temporary file.
2979           */
2980           *component='\0';
2981           status=ImageToFile(image,component,exception);
2982           (void) CloseBlob(image);
2983           if (status == MagickFalse)
2984             {
2985               image=DestroyImage(image);
2986               return(MagickFalse);
2987             }
2988           SetImageInfoFile(image_info,(FILE *) NULL);
2989           (void) CopyMagickString(image->filename,component,MagickPathExtent);
2990           status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
2991           if (status == MagickFalse)
2992             {
2993               image=DestroyImage(image);
2994               return(MagickFalse);
2995             }
2996           (void) CopyMagickString(image_info->filename,component,
2997             MagickPathExtent);
2998           image_info->temporary=MagickTrue;
2999         }
3000       magick=(unsigned char *) AcquireMagickMemory(magick_size);
3001       if (magick == (unsigned char *) NULL)
3002         {
3003           (void) CloseBlob(image);
3004           image=DestroyImage(image);
3005           return(MagickFalse);
3006         }
3007       (void) memset(magick,0,magick_size);
3008       count=ReadBlob(image,magick_size,magick);
3009       (void) SeekBlob(image,-((MagickOffsetType) count),SEEK_CUR);
3010       (void) CloseBlob(image);
3011       image=DestroyImage(image);
3012       /*
3013         Check magic cache.
3014       */
3015       sans_exception=AcquireExceptionInfo();
3016       magic_info=GetMagicInfo(magick,(size_t) count,sans_exception);
3017       magick=(unsigned char *) RelinquishMagickMemory(magick);
3018       if ((magic_info != (const MagicInfo *) NULL) &&
3019           (GetMagicName(magic_info) != (char *) NULL))
3020         {
3021           /*
3022             Try to use magick_info that was determined earlier by the extension
3023           */
3024           if ((magick_info != (const MagickInfo *) NULL) &&
3025               (GetMagickUseExtension(magick_info) != MagickFalse) &&
3026               (LocaleCompare(magick_info->magick_module,GetMagicName(
3027                 magic_info)) == 0))
3028             (void) CopyMagickString(image_info->magick,magick_info->name,
3029               MagickPathExtent);
3030           else
3031             {
3032               (void) CopyMagickString(image_info->magick,GetMagicName(
3033                 magic_info),MagickPathExtent);
3034               magick_info=GetMagickInfo(image_info->magick,sans_exception);
3035             }
3036           if ((magick_info == (const MagickInfo *) NULL) ||
3037               (GetMagickEndianSupport(magick_info) == MagickFalse))
3038             image_info->endian=UndefinedEndian;
3039           sans_exception=DestroyExceptionInfo(sans_exception);
3040           return(MagickTrue);
3041         }
3042       magick_info=GetMagickInfo(image_info->magick,sans_exception);
3043       if ((magick_info == (const MagickInfo *) NULL) ||
3044           (GetMagickEndianSupport(magick_info) == MagickFalse))
3045         image_info->endian=UndefinedEndian;
3046       sans_exception=DestroyExceptionInfo(sans_exception);
3047     }
3048   return(MagickTrue);
3049 }
3050 
3051 /*
3052 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3053 %                                                                             %
3054 %                                                                             %
3055 %                                                                             %
3056 %   S e t I m a g e I n f o B l o b                                           %
3057 %                                                                             %
3058 %                                                                             %
3059 %                                                                             %
3060 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3061 %
3062 %  SetImageInfoBlob() sets the image info blob member.
3063 %
3064 %  The format of the SetImageInfoBlob method is:
3065 %
3066 %      void SetImageInfoBlob(ImageInfo *image_info,const void *blob,
3067 %        const size_t length)
3068 %
3069 %  A description of each parameter follows:
3070 %
3071 %    o image_info: the image info.
3072 %
3073 %    o blob: the blob.
3074 %
3075 %    o length: the blob length.
3076 %
3077 */
SetImageInfoBlob(ImageInfo * image_info,const void * blob,const size_t length)3078 MagickExport void SetImageInfoBlob(ImageInfo *image_info,const void *blob,
3079   const size_t length)
3080 {
3081   assert(image_info != (ImageInfo *) NULL);
3082   assert(image_info->signature == MagickCoreSignature);
3083   if (image_info->debug != MagickFalse)
3084     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
3085       image_info->filename);
3086   image_info->blob=(void *) blob;
3087   image_info->length=length;
3088 }
3089 
3090 /*
3091 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3092 %                                                                             %
3093 %                                                                             %
3094 %                                                                             %
3095 %   S e t I m a g e I n f o C u s t o m S t r e a m                           %
3096 %                                                                             %
3097 %                                                                             %
3098 %                                                                             %
3099 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3100 %
3101 %  SetImageInfoCustomStream() sets the image info custom stream handlers.
3102 %
3103 %  The format of the SetImageInfoCustomStream method is:
3104 %
3105 %      void SetImageInfoCustomStream(ImageInfo *image_info,
3106 %        CustomStreamInfo *custom_stream)
3107 %
3108 %  A description of each parameter follows:
3109 %
3110 %    o image_info: the image info.
3111 %
3112 %    o custom_stream: your custom stream methods.
3113 %
3114 */
SetImageInfoCustomStream(ImageInfo * image_info,CustomStreamInfo * custom_stream)3115 MagickExport void SetImageInfoCustomStream(ImageInfo *image_info,
3116   CustomStreamInfo *custom_stream)
3117 {
3118   assert(image_info != (ImageInfo *) NULL);
3119   assert(image_info->signature == MagickCoreSignature);
3120   if (image_info->debug != MagickFalse)
3121     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
3122       image_info->filename);
3123   image_info->custom_stream=(CustomStreamInfo *) custom_stream;
3124 }
3125 
3126 /*
3127 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3128 %                                                                             %
3129 %                                                                             %
3130 %                                                                             %
3131 %   S e t I m a g e I n f o F i l e                                           %
3132 %                                                                             %
3133 %                                                                             %
3134 %                                                                             %
3135 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3136 %
3137 %  SetImageInfoFile() sets the image info file member.
3138 %
3139 %  The format of the SetImageInfoFile method is:
3140 %
3141 %      void SetImageInfoFile(ImageInfo *image_info,FILE *file)
3142 %
3143 %  A description of each parameter follows:
3144 %
3145 %    o image_info: the image info.
3146 %
3147 %    o file: the file.
3148 %
3149 */
SetImageInfoFile(ImageInfo * image_info,FILE * file)3150 MagickExport void SetImageInfoFile(ImageInfo *image_info,FILE *file)
3151 {
3152   assert(image_info != (ImageInfo *) NULL);
3153   assert(image_info->signature == MagickCoreSignature);
3154   if (image_info->debug != MagickFalse)
3155     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
3156       image_info->filename);
3157   image_info->file=file;
3158 }
3159 
3160 /*
3161 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3162 %                                                                             %
3163 %                                                                             %
3164 %                                                                             %
3165 %   S e t I m a g e M a s k                                                   %
3166 %                                                                             %
3167 %                                                                             %
3168 %                                                                             %
3169 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3170 %
3171 %  SetImageMask() associates a mask with the image.  The mask must be the same
3172 %  dimensions as the image.
3173 %
3174 %  The format of the SetImageMask method is:
3175 %
3176 %      MagickBooleanType SetImageMask(Image *image,const PixelMask type,
3177 %        const Image *mask,ExceptionInfo *exception)
3178 %
3179 %  A description of each parameter follows:
3180 %
3181 %    o image: the image.
3182 %
3183 %    o type: the mask type, ReadPixelMask or WritePixelMask.
3184 %
3185 %    o mask: the image mask.
3186 %
3187 %    o exception: return any errors or warnings in this structure.
3188 %
3189 */
SetImageMask(Image * image,const PixelMask type,const Image * mask,ExceptionInfo * exception)3190 MagickExport MagickBooleanType SetImageMask(Image *image,const PixelMask type,
3191   const Image *mask,ExceptionInfo *exception)
3192 {
3193   CacheView
3194     *mask_view,
3195     *image_view;
3196 
3197   MagickBooleanType
3198     status;
3199 
3200   ssize_t
3201     y;
3202 
3203   /*
3204     Set image mask.
3205   */
3206   assert(image != (Image *) NULL);
3207   if (image->debug != MagickFalse)
3208     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
3209   assert(image->signature == MagickCoreSignature);
3210   if (mask == (const Image *) NULL)
3211     {
3212       switch (type)
3213       {
3214         case ReadPixelMask:
3215         {
3216           image->channels=(ChannelType) (image->channels & ~ReadMaskChannel);
3217           break;
3218         }
3219         case WritePixelMask:
3220         {
3221           image->channels=(ChannelType) (image->channels & ~WriteMaskChannel);
3222         }
3223         default:
3224         {
3225           image->channels=(ChannelType) (image->channels & ~CompositeMaskChannel);
3226           break;
3227         }
3228       }
3229       return(SyncImagePixelCache(image,exception));
3230     }
3231   switch (type)
3232   {
3233     case ReadPixelMask:
3234     {
3235       image->channels=(ChannelType) (image->channels | ReadMaskChannel);
3236       break;
3237     }
3238     case WritePixelMask:
3239     {
3240       image->channels=(ChannelType) (image->channels | WriteMaskChannel);
3241       break;
3242     }
3243     default:
3244     {
3245       image->channels=(ChannelType) (image->channels | CompositeMaskChannel);
3246       break;
3247     }
3248   }
3249   if (SyncImagePixelCache(image,exception) == MagickFalse)
3250     return(MagickFalse);
3251   status=MagickTrue;
3252   image->mask_trait=UpdatePixelTrait;
3253   mask_view=AcquireVirtualCacheView(mask,exception);
3254   image_view=AcquireAuthenticCacheView(image,exception);
3255 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3256   #pragma omp parallel for schedule(static) shared(status) \
3257     magick_number_threads(mask,image,image->rows,1)
3258 #endif
3259   for (y=0; y < (ssize_t) image->rows; y++)
3260   {
3261     register const Quantum
3262       *magick_restrict p;
3263 
3264     register Quantum
3265       *magick_restrict q;
3266 
3267     register ssize_t
3268       x;
3269 
3270     if (status == MagickFalse)
3271       continue;
3272     p=GetCacheViewVirtualPixels(mask_view,0,y,mask->columns,1,exception);
3273     q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
3274     if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
3275       {
3276         status=MagickFalse;
3277         continue;
3278       }
3279     for (x=0; x < (ssize_t) image->columns; x++)
3280     {
3281       MagickRealType
3282         intensity;
3283 
3284       intensity=0.0;
3285       if ((x < (ssize_t) mask->columns) && (y < (ssize_t) mask->rows))
3286         intensity=GetPixelIntensity(mask,p);
3287       switch (type)
3288       {
3289         case ReadPixelMask:
3290         {
3291           SetPixelReadMask(image,ClampToQuantum(intensity),q);
3292           break;
3293         }
3294         case WritePixelMask:
3295         {
3296           SetPixelWriteMask(image,ClampToQuantum(intensity),q);
3297           break;
3298         }
3299         default:
3300         {
3301           SetPixelCompositeMask(image,ClampToQuantum(intensity),q);
3302           break;
3303         }
3304       }
3305       p+=GetPixelChannels(mask);
3306       q+=GetPixelChannels(image);
3307     }
3308     if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
3309       status=MagickFalse;
3310   }
3311   image->mask_trait=UndefinedPixelTrait;
3312   mask_view=DestroyCacheView(mask_view);
3313   image_view=DestroyCacheView(image_view);
3314   return(status);
3315 }
3316 
3317 /*
3318 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3319 %                                                                             %
3320 %                                                                             %
3321 %                                                                             %
3322 %   S e t I m a g e R e g i o n M a s k                                       %
3323 %                                                                             %
3324 %                                                                             %
3325 %                                                                             %
3326 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3327 %
3328 %  SetImageRegionMask() associates a mask with the image as defined by the
3329 %  specified region.
3330 %
3331 %  The format of the SetImageRegionMask method is:
3332 %
3333 %      MagickBooleanType SetImageRegionMask(Image *image,const PixelMask type,
3334 %        const RectangleInfo *region,ExceptionInfo *exception)
3335 %
3336 %  A description of each parameter follows:
3337 %
3338 %    o image: the image.
3339 %
3340 %    o type: the mask type, ReadPixelMask or WritePixelMask.
3341 %
3342 %    o geometry: the mask region.
3343 %
3344 %    o exception: return any errors or warnings in this structure.
3345 %
3346 */
SetImageRegionMask(Image * image,const PixelMask type,const RectangleInfo * region,ExceptionInfo * exception)3347 MagickExport MagickBooleanType SetImageRegionMask(Image *image,
3348   const PixelMask type,const RectangleInfo *region,ExceptionInfo *exception)
3349 {
3350   CacheView
3351     *image_view;
3352 
3353   MagickBooleanType
3354     status;
3355 
3356   ssize_t
3357     y;
3358 
3359   /*
3360     Set image mask as defined by the region.
3361   */
3362   assert(image != (Image *) NULL);
3363   if (image->debug != MagickFalse)
3364     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
3365   assert(image->signature == MagickCoreSignature);
3366   if (region == (const RectangleInfo *) NULL)
3367     {
3368       switch (type)
3369       {
3370         case ReadPixelMask:
3371         {
3372           image->channels=(ChannelType) (image->channels & ~ReadMaskChannel);
3373           break;
3374         }
3375         case WritePixelMask:
3376         {
3377           image->channels=(ChannelType) (image->channels & ~WriteMaskChannel);
3378           break;
3379         }
3380         default:
3381         {
3382           image->channels=(ChannelType) (image->channels & ~CompositeMaskChannel);
3383           break;
3384         }
3385       }
3386       return(SyncImagePixelCache(image,exception));
3387     }
3388   switch (type)
3389   {
3390     case ReadPixelMask:
3391     {
3392       image->channels=(ChannelType) (image->channels | ReadMaskChannel);
3393       break;
3394     }
3395     case WritePixelMask:
3396     {
3397       image->channels=(ChannelType) (image->channels | WriteMaskChannel);
3398       break;
3399     }
3400     default:
3401     {
3402       image->channels=(ChannelType) (image->channels | CompositeMaskChannel);
3403       break;
3404     }
3405   }
3406   if (SyncImagePixelCache(image,exception) == MagickFalse)
3407     return(MagickFalse);
3408   status=MagickTrue;
3409   image->mask_trait=UpdatePixelTrait;
3410   image_view=AcquireAuthenticCacheView(image,exception);
3411 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3412   #pragma omp parallel for schedule(static) shared(status) \
3413     magick_number_threads(image,image,image->rows,1)
3414 #endif
3415   for (y=0; y < (ssize_t) image->rows; y++)
3416   {
3417     register Quantum
3418       *magick_restrict q;
3419 
3420     register ssize_t
3421       x;
3422 
3423     if (status == MagickFalse)
3424       continue;
3425     q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
3426     if (q == (Quantum *) NULL)
3427       {
3428         status=MagickFalse;
3429         continue;
3430       }
3431     for (x=0; x < (ssize_t) image->columns; x++)
3432     {
3433       Quantum
3434         pixel;
3435 
3436       pixel=QuantumRange;
3437       if (((x >= region->x) && (x < (region->x+(ssize_t) region->width))) &&
3438           ((y >= region->y) && (y < (region->y+(ssize_t) region->height))))
3439         pixel=(Quantum) 0;
3440       switch (type)
3441       {
3442         case ReadPixelMask:
3443         {
3444           SetPixelReadMask(image,pixel,q);
3445           break;
3446         }
3447         case WritePixelMask:
3448         {
3449           SetPixelWriteMask(image,pixel,q);
3450           break;
3451         }
3452         default:
3453         {
3454           SetPixelCompositeMask(image,pixel,q);
3455           break;
3456         }
3457       }
3458       q+=GetPixelChannels(image);
3459     }
3460     if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
3461       status=MagickFalse;
3462   }
3463   image->mask_trait=UndefinedPixelTrait;
3464   image_view=DestroyCacheView(image_view);
3465   return(status);
3466 }
3467 
3468 /*
3469 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3470 %                                                                             %
3471 %                                                                             %
3472 %                                                                             %
3473 %   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                       %
3474 %                                                                             %
3475 %                                                                             %
3476 %                                                                             %
3477 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3478 %
3479 %  SetImageVirtualPixelMethod() sets the "virtual pixels" method for the
3480 %  image and returns the previous setting.  A virtual pixel is any pixel access
3481 %  that is outside the boundaries of the image cache.
3482 %
3483 %  The format of the SetImageVirtualPixelMethod() method is:
3484 %
3485 %      VirtualPixelMethod SetImageVirtualPixelMethod(Image *image,
3486 %        const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
3487 %
3488 %  A description of each parameter follows:
3489 %
3490 %    o image: the image.
3491 %
3492 %    o virtual_pixel_method: choose the type of virtual pixel.
3493 %
3494 %    o exception: return any errors or warnings in this structure.
3495 %
3496 */
SetImageVirtualPixelMethod(Image * image,const VirtualPixelMethod virtual_pixel_method,ExceptionInfo * exception)3497 MagickExport VirtualPixelMethod SetImageVirtualPixelMethod(Image *image,
3498   const VirtualPixelMethod virtual_pixel_method,ExceptionInfo *exception)
3499 {
3500   assert(image != (const Image *) NULL);
3501   assert(image->signature == MagickCoreSignature);
3502   if (image->debug != MagickFalse)
3503     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3504   return(SetPixelCacheVirtualMethod(image,virtual_pixel_method,exception));
3505 }
3506 
3507 /*
3508 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3509 %                                                                             %
3510 %                                                                             %
3511 %                                                                             %
3512 %     S m u s h I m a g e s                                                   %
3513 %                                                                             %
3514 %                                                                             %
3515 %                                                                             %
3516 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3517 %
3518 %  SmushImages() takes all images from the current image pointer to the end
3519 %  of the image list and smushes them to each other top-to-bottom if the
3520 %  stack parameter is true, otherwise left-to-right.
3521 %
3522 %  The current gravity setting now effects how the image is justified in the
3523 %  final image.
3524 %
3525 %  The format of the SmushImages method is:
3526 %
3527 %      Image *SmushImages(const Image *images,const MagickBooleanType stack,
3528 %        ExceptionInfo *exception)
3529 %
3530 %  A description of each parameter follows:
3531 %
3532 %    o images: the image sequence.
3533 %
3534 %    o stack: A value other than 0 stacks the images top-to-bottom.
3535 %
3536 %    o offset: minimum distance in pixels between images.
3537 %
3538 %    o exception: return any errors or warnings in this structure.
3539 %
3540 */
3541 
SmushXGap(const Image * smush_image,const Image * images,const ssize_t offset,ExceptionInfo * exception)3542 static ssize_t SmushXGap(const Image *smush_image,const Image *images,
3543   const ssize_t offset,ExceptionInfo *exception)
3544 {
3545   CacheView
3546     *left_view,
3547     *right_view;
3548 
3549   const Image
3550     *left_image,
3551     *right_image;
3552 
3553   RectangleInfo
3554     left_geometry,
3555     right_geometry;
3556 
3557   register const Quantum
3558     *p;
3559 
3560   register ssize_t
3561     i,
3562     y;
3563 
3564   size_t
3565     gap;
3566 
3567   ssize_t
3568     x;
3569 
3570   if (images->previous == (Image *) NULL)
3571     return(0);
3572   right_image=images;
3573   SetGeometry(smush_image,&right_geometry);
3574   GravityAdjustGeometry(right_image->columns,right_image->rows,
3575     right_image->gravity,&right_geometry);
3576   left_image=images->previous;
3577   SetGeometry(smush_image,&left_geometry);
3578   GravityAdjustGeometry(left_image->columns,left_image->rows,
3579     left_image->gravity,&left_geometry);
3580   gap=right_image->columns;
3581   left_view=AcquireVirtualCacheView(left_image,exception);
3582   right_view=AcquireVirtualCacheView(right_image,exception);
3583   for (y=0; y < (ssize_t) smush_image->rows; y++)
3584   {
3585     for (x=(ssize_t) left_image->columns-1; x > 0; x--)
3586     {
3587       p=GetCacheViewVirtualPixels(left_view,x,left_geometry.y+y,1,1,exception);
3588       if ((p == (const Quantum *) NULL) ||
3589           (GetPixelAlpha(left_image,p) != TransparentAlpha) ||
3590           ((left_image->columns-x-1) >= gap))
3591         break;
3592     }
3593     i=(ssize_t) left_image->columns-x-1;
3594     for (x=0; x < (ssize_t) right_image->columns; x++)
3595     {
3596       p=GetCacheViewVirtualPixels(right_view,x,right_geometry.y+y,1,1,
3597         exception);
3598       if ((p == (const Quantum *) NULL) ||
3599           (GetPixelAlpha(right_image,p) != TransparentAlpha) ||
3600           ((x+i) >= (ssize_t) gap))
3601         break;
3602     }
3603     if ((x+i) < (ssize_t) gap)
3604       gap=(size_t) (x+i);
3605   }
3606   right_view=DestroyCacheView(right_view);
3607   left_view=DestroyCacheView(left_view);
3608   if (y < (ssize_t) smush_image->rows)
3609     return(offset);
3610   return((ssize_t) gap-offset);
3611 }
3612 
SmushYGap(const Image * smush_image,const Image * images,const ssize_t offset,ExceptionInfo * exception)3613 static ssize_t SmushYGap(const Image *smush_image,const Image *images,
3614   const ssize_t offset,ExceptionInfo *exception)
3615 {
3616   CacheView
3617     *bottom_view,
3618     *top_view;
3619 
3620   const Image
3621     *bottom_image,
3622     *top_image;
3623 
3624   RectangleInfo
3625     bottom_geometry,
3626     top_geometry;
3627 
3628   register const Quantum
3629     *p;
3630 
3631   register ssize_t
3632     i,
3633     x;
3634 
3635   size_t
3636     gap;
3637 
3638   ssize_t
3639     y;
3640 
3641   if (images->previous == (Image *) NULL)
3642     return(0);
3643   bottom_image=images;
3644   SetGeometry(smush_image,&bottom_geometry);
3645   GravityAdjustGeometry(bottom_image->columns,bottom_image->rows,
3646     bottom_image->gravity,&bottom_geometry);
3647   top_image=images->previous;
3648   SetGeometry(smush_image,&top_geometry);
3649   GravityAdjustGeometry(top_image->columns,top_image->rows,top_image->gravity,
3650     &top_geometry);
3651   gap=bottom_image->rows;
3652   top_view=AcquireVirtualCacheView(top_image,exception);
3653   bottom_view=AcquireVirtualCacheView(bottom_image,exception);
3654   for (x=0; x < (ssize_t) smush_image->columns; x++)
3655   {
3656     for (y=(ssize_t) top_image->rows-1; y > 0; y--)
3657     {
3658       p=GetCacheViewVirtualPixels(top_view,top_geometry.x+x,y,1,1,exception);
3659       if ((p == (const Quantum *) NULL) ||
3660           (GetPixelAlpha(top_image,p) != TransparentAlpha) ||
3661           ((top_image->rows-y-1) >= gap))
3662         break;
3663     }
3664     i=(ssize_t) top_image->rows-y-1;
3665     for (y=0; y < (ssize_t) bottom_image->rows; y++)
3666     {
3667       p=GetCacheViewVirtualPixels(bottom_view,bottom_geometry.x+x,y,1,1,
3668         exception);
3669       if ((p == (const Quantum *) NULL) ||
3670           (GetPixelAlpha(bottom_image,p) != TransparentAlpha) ||
3671           ((y+i) >= (ssize_t) gap))
3672         break;
3673     }
3674     if ((y+i) < (ssize_t) gap)
3675       gap=(size_t) (y+i);
3676   }
3677   bottom_view=DestroyCacheView(bottom_view);
3678   top_view=DestroyCacheView(top_view);
3679   if (x < (ssize_t) smush_image->columns)
3680     return(offset);
3681   return((ssize_t) gap-offset);
3682 }
3683 
SmushImages(const Image * images,const MagickBooleanType stack,const ssize_t offset,ExceptionInfo * exception)3684 MagickExport Image *SmushImages(const Image *images,
3685   const MagickBooleanType stack,const ssize_t offset,ExceptionInfo *exception)
3686 {
3687 #define SmushImageTag  "Smush/Image"
3688 
3689   const Image
3690     *image;
3691 
3692   Image
3693     *smush_image;
3694 
3695   MagickBooleanType
3696     proceed,
3697     status;
3698 
3699   MagickOffsetType
3700     n;
3701 
3702   PixelTrait
3703     alpha_trait;
3704 
3705   RectangleInfo
3706     geometry;
3707 
3708   register const Image
3709     *next;
3710 
3711   size_t
3712     height,
3713     number_images,
3714     width;
3715 
3716   ssize_t
3717     x_offset,
3718     y_offset;
3719 
3720   /*
3721     Compute maximum area of smushed area.
3722   */
3723   assert(images != (Image *) NULL);
3724   assert(images->signature == MagickCoreSignature);
3725   if (images->debug != MagickFalse)
3726     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
3727   assert(exception != (ExceptionInfo *) NULL);
3728   assert(exception->signature == MagickCoreSignature);
3729   image=images;
3730   alpha_trait=image->alpha_trait;
3731   number_images=1;
3732   width=image->columns;
3733   height=image->rows;
3734   next=GetNextImageInList(image);
3735   for ( ; next != (Image *) NULL; next=GetNextImageInList(next))
3736   {
3737     if (next->alpha_trait != UndefinedPixelTrait)
3738       alpha_trait=BlendPixelTrait;
3739     number_images++;
3740     if (stack != MagickFalse)
3741       {
3742         if (next->columns > width)
3743           width=next->columns;
3744         height+=next->rows;
3745         if (next->previous != (Image *) NULL)
3746           height+=offset;
3747         continue;
3748       }
3749     width+=next->columns;
3750     if (next->previous != (Image *) NULL)
3751       width+=offset;
3752     if (next->rows > height)
3753       height=next->rows;
3754   }
3755   /*
3756     Smush images.
3757   */
3758   smush_image=CloneImage(image,width,height,MagickTrue,exception);
3759   if (smush_image == (Image *) NULL)
3760     return((Image *) NULL);
3761   if (SetImageStorageClass(smush_image,DirectClass,exception) == MagickFalse)
3762     {
3763       smush_image=DestroyImage(smush_image);
3764       return((Image *) NULL);
3765     }
3766   smush_image->alpha_trait=alpha_trait;
3767   (void) SetImageBackgroundColor(smush_image,exception);
3768   status=MagickTrue;
3769   x_offset=0;
3770   y_offset=0;
3771   for (n=0; n < (MagickOffsetType) number_images; n++)
3772   {
3773     SetGeometry(smush_image,&geometry);
3774     GravityAdjustGeometry(image->columns,image->rows,image->gravity,&geometry);
3775     if (stack != MagickFalse)
3776       {
3777         x_offset-=geometry.x;
3778         y_offset-=SmushYGap(smush_image,image,offset,exception);
3779       }
3780     else
3781       {
3782         x_offset-=SmushXGap(smush_image,image,offset,exception);
3783         y_offset-=geometry.y;
3784       }
3785     status=CompositeImage(smush_image,image,OverCompositeOp,MagickTrue,x_offset,
3786       y_offset,exception);
3787     proceed=SetImageProgress(image,SmushImageTag,n,number_images);
3788     if (proceed == MagickFalse)
3789       break;
3790     if (stack == MagickFalse)
3791       {
3792         x_offset+=(ssize_t) image->columns;
3793         y_offset=0;
3794       }
3795     else
3796       {
3797         x_offset=0;
3798         y_offset+=(ssize_t) image->rows;
3799       }
3800     image=GetNextImageInList(image);
3801   }
3802   if (stack == MagickFalse)
3803     smush_image->columns=(size_t) x_offset;
3804   else
3805     smush_image->rows=(size_t) y_offset;
3806   if (status == MagickFalse)
3807     smush_image=DestroyImage(smush_image);
3808   return(smush_image);
3809 }
3810 
3811 /*
3812 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3813 %                                                                             %
3814 %                                                                             %
3815 %                                                                             %
3816 %   S t r i p I m a g e                                                       %
3817 %                                                                             %
3818 %                                                                             %
3819 %                                                                             %
3820 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3821 %
3822 %  StripImage() strips an image of all profiles and comments.
3823 %
3824 %  The format of the StripImage method is:
3825 %
3826 %      MagickBooleanType StripImage(Image *image,ExceptionInfo *exception)
3827 %
3828 %  A description of each parameter follows:
3829 %
3830 %    o image: the image.
3831 %
3832 %    o exception: return any errors or warnings in this structure.
3833 %
3834 */
StripImage(Image * image,ExceptionInfo * exception)3835 MagickExport MagickBooleanType StripImage(Image *image,ExceptionInfo *exception)
3836 {
3837   MagickBooleanType
3838     status;
3839 
3840   assert(image != (Image *) NULL);
3841   if (image->debug != MagickFalse)
3842     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
3843   (void) exception;
3844   DestroyImageProfiles(image);
3845   (void) DeleteImageProperty(image,"comment");
3846   (void) DeleteImageProperty(image,"date:create");
3847   (void) DeleteImageProperty(image,"date:modify");
3848   status=SetImageArtifact(image,"png:exclude-chunk",
3849     "bKGD,caNv,cHRM,eXIf,gAMA,iCCP,iTXt,pHYs,sRGB,tEXt,zCCP,zTXt,date");
3850   return(status);
3851 }
3852 
3853 /*
3854 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3855 %                                                                             %
3856 %                                                                             %
3857 %                                                                             %
3858 +   S y n c I m a g e                                                         %
3859 %                                                                             %
3860 %                                                                             %
3861 %                                                                             %
3862 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3863 %
3864 %  SyncImage() initializes the red, green, and blue intensities of each pixel
3865 %  as defined by the colormap index.
3866 %
3867 %  The format of the SyncImage method is:
3868 %
3869 %      MagickBooleanType SyncImage(Image *image,ExceptionInfo *exception)
3870 %
3871 %  A description of each parameter follows:
3872 %
3873 %    o image: the image.
3874 %
3875 %    o exception: return any errors or warnings in this structure.
3876 %
3877 */
3878 
PushColormapIndex(Image * image,const Quantum index,MagickBooleanType * range_exception)3879 static inline Quantum PushColormapIndex(Image *image,const Quantum index,
3880   MagickBooleanType *range_exception)
3881 {
3882   if ((size_t) index < image->colors)
3883     return(index);
3884   *range_exception=MagickTrue;
3885   return((Quantum) 0);
3886 }
3887 
SyncImage(Image * image,ExceptionInfo * exception)3888 MagickExport MagickBooleanType SyncImage(Image *image,ExceptionInfo *exception)
3889 {
3890   CacheView
3891     *image_view;
3892 
3893   MagickBooleanType
3894     range_exception,
3895     status,
3896     taint;
3897 
3898   ssize_t
3899     y;
3900 
3901   assert(image != (Image *) NULL);
3902   if (image->debug != MagickFalse)
3903     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
3904   assert(image->signature == MagickCoreSignature);
3905   if (image->ping != MagickFalse)
3906     return(MagickTrue);
3907   if (image->storage_class != PseudoClass)
3908     return(MagickFalse);
3909   assert(image->colormap != (PixelInfo *) NULL);
3910   range_exception=MagickFalse;
3911   status=MagickTrue;
3912   taint=image->taint;
3913   image_view=AcquireAuthenticCacheView(image,exception);
3914 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3915   #pragma omp parallel for schedule(static) shared(range_exception,status) \
3916     magick_number_threads(image,image,image->rows,1)
3917 #endif
3918   for (y=0; y < (ssize_t) image->rows; y++)
3919   {
3920     Quantum
3921       index;
3922 
3923     register Quantum
3924       *magick_restrict q;
3925 
3926     register ssize_t
3927       x;
3928 
3929     if (status == MagickFalse)
3930       continue;
3931     q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
3932     if (q == (Quantum *) NULL)
3933       {
3934         status=MagickFalse;
3935         continue;
3936       }
3937     for (x=0; x < (ssize_t) image->columns; x++)
3938     {
3939       index=PushColormapIndex(image,GetPixelIndex(image,q),&range_exception);
3940       SetPixelViaPixelInfo(image,image->colormap+(ssize_t) index,q);
3941       q+=GetPixelChannels(image);
3942     }
3943     if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
3944       status=MagickFalse;
3945   }
3946   image_view=DestroyCacheView(image_view);
3947   image->taint=taint;
3948   if ((image->ping == MagickFalse) && (range_exception != MagickFalse))
3949     (void) ThrowMagickException(exception,GetMagickModule(),
3950       CorruptImageWarning,"InvalidColormapIndex","`%s'",image->filename);
3951   return(status);
3952 }
3953 
3954 /*
3955 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3956 %                                                                             %
3957 %                                                                             %
3958 %                                                                             %
3959 %   S y n c I m a g e S e t t i n g s                                         %
3960 %                                                                             %
3961 %                                                                             %
3962 %                                                                             %
3963 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3964 %
3965 %  SyncImageSettings() syncs any image_info global options into per-image
3966 %  attributes.
3967 %
3968 %  Note: in IMv6 free form 'options' were always mapped into 'artifacts', so
3969 %  that operations and coders can find such settings.  In IMv7 if a desired
3970 %  per-image artifact is not set, then it will directly look for a global
3971 %  option as a fallback, as such this copy is no longer needed, only the
3972 %  link set up.
3973 %
3974 %  The format of the SyncImageSettings method is:
3975 %
3976 %      MagickBooleanType SyncImageSettings(const ImageInfo *image_info,
3977 %        Image *image,ExceptionInfo *exception)
3978 %      MagickBooleanType SyncImagesSettings(const ImageInfo *image_info,
3979 %        Image *image,ExceptionInfo *exception)
3980 %
3981 %  A description of each parameter follows:
3982 %
3983 %    o image_info: the image info.
3984 %
3985 %    o image: the image.
3986 %
3987 %    o exception: return any errors or warnings in this structure.
3988 %
3989 */
3990 
SyncImagesSettings(ImageInfo * image_info,Image * images,ExceptionInfo * exception)3991 MagickExport MagickBooleanType SyncImagesSettings(ImageInfo *image_info,
3992   Image *images,ExceptionInfo *exception)
3993 {
3994   Image
3995     *image;
3996 
3997   assert(image_info != (const ImageInfo *) NULL);
3998   assert(image_info->signature == MagickCoreSignature);
3999   assert(images != (Image *) NULL);
4000   assert(images->signature == MagickCoreSignature);
4001   if (images->debug != MagickFalse)
4002     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
4003   image=images;
4004   for ( ; image != (Image *) NULL; image=GetNextImageInList(image))
4005     (void) SyncImageSettings(image_info,image,exception);
4006   (void) DeleteImageOption(image_info,"page");
4007   return(MagickTrue);
4008 }
4009 
SyncImageSettings(const ImageInfo * image_info,Image * image,ExceptionInfo * exception)4010 MagickExport MagickBooleanType SyncImageSettings(const ImageInfo *image_info,
4011   Image *image,ExceptionInfo *exception)
4012 {
4013   const char
4014     *option;
4015 
4016   GeometryInfo
4017     geometry_info;
4018 
4019   MagickStatusType
4020     flags;
4021 
4022   ResolutionType
4023     units;
4024 
4025   /*
4026     Sync image options.
4027   */
4028   assert(image_info != (const ImageInfo *) NULL);
4029   assert(image_info->signature == MagickCoreSignature);
4030   assert(image != (Image *) NULL);
4031   assert(image->signature == MagickCoreSignature);
4032   if (image->debug != MagickFalse)
4033     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4034   option=GetImageOption(image_info,"background");
4035   if (option != (const char *) NULL)
4036     (void) QueryColorCompliance(option,AllCompliance,&image->background_color,
4037       exception);
4038   option=GetImageOption(image_info,"black-point-compensation");
4039   if (option != (const char *) NULL)
4040     image->black_point_compensation=(MagickBooleanType) ParseCommandOption(
4041       MagickBooleanOptions,MagickFalse,option);
4042   option=GetImageOption(image_info,"blue-primary");
4043   if (option != (const char *) NULL)
4044     {
4045       flags=ParseGeometry(option,&geometry_info);
4046       image->chromaticity.blue_primary.x=geometry_info.rho;
4047       image->chromaticity.blue_primary.y=geometry_info.sigma;
4048       if ((flags & SigmaValue) == 0)
4049         image->chromaticity.blue_primary.y=image->chromaticity.blue_primary.x;
4050     }
4051   option=GetImageOption(image_info,"bordercolor");
4052   if (option != (const char *) NULL)
4053     (void) QueryColorCompliance(option,AllCompliance,&image->border_color,
4054       exception);
4055   /* FUTURE: do not sync compose to per-image compose setting here */
4056   option=GetImageOption(image_info,"compose");
4057   if (option != (const char *) NULL)
4058     image->compose=(CompositeOperator) ParseCommandOption(MagickComposeOptions,
4059       MagickFalse,option);
4060   /* -- */
4061   option=GetImageOption(image_info,"compress");
4062   if (option != (const char *) NULL)
4063     image->compression=(CompressionType) ParseCommandOption(
4064       MagickCompressOptions,MagickFalse,option);
4065   option=GetImageOption(image_info,"debug");
4066   if (option != (const char *) NULL)
4067     image->debug=(MagickBooleanType) ParseCommandOption(MagickBooleanOptions,
4068       MagickFalse,option);
4069   option=GetImageOption(image_info,"density");
4070   if (option != (const char *) NULL)
4071     {
4072       flags=ParseGeometry(option,&geometry_info);
4073       image->resolution.x=geometry_info.rho;
4074       image->resolution.y=geometry_info.sigma;
4075       if ((flags & SigmaValue) == 0)
4076         image->resolution.y=image->resolution.x;
4077     }
4078   option=GetImageOption(image_info,"depth");
4079   if (option != (const char *) NULL)
4080     image->depth=StringToUnsignedLong(option);
4081   option=GetImageOption(image_info,"endian");
4082   if (option != (const char *) NULL)
4083     image->endian=(EndianType) ParseCommandOption(MagickEndianOptions,
4084       MagickFalse,option);
4085   option=GetImageOption(image_info,"filter");
4086   if (option != (const char *) NULL)
4087     image->filter=(FilterType) ParseCommandOption(MagickFilterOptions,
4088       MagickFalse,option);
4089   option=GetImageOption(image_info,"fuzz");
4090   if (option != (const char *) NULL)
4091     image->fuzz=StringToDoubleInterval(option,(double) QuantumRange+1.0);
4092   option=GetImageOption(image_info,"gravity");
4093   if (option != (const char *) NULL)
4094     image->gravity=(GravityType) ParseCommandOption(MagickGravityOptions,
4095       MagickFalse,option);
4096   option=GetImageOption(image_info,"green-primary");
4097   if (option != (const char *) NULL)
4098     {
4099       flags=ParseGeometry(option,&geometry_info);
4100       image->chromaticity.green_primary.x=geometry_info.rho;
4101       image->chromaticity.green_primary.y=geometry_info.sigma;
4102       if ((flags & SigmaValue) == 0)
4103         image->chromaticity.green_primary.y=image->chromaticity.green_primary.x;
4104     }
4105   option=GetImageOption(image_info,"intent");
4106   if (option != (const char *) NULL)
4107     image->rendering_intent=(RenderingIntent) ParseCommandOption(
4108       MagickIntentOptions,MagickFalse,option);
4109   option=GetImageOption(image_info,"intensity");
4110   if (option != (const char *) NULL)
4111     image->intensity=(PixelIntensityMethod) ParseCommandOption(
4112       MagickPixelIntensityOptions,MagickFalse,option);
4113   option=GetImageOption(image_info,"interlace");
4114   if (option != (const char *) NULL)
4115     image->interlace=(InterlaceType) ParseCommandOption(MagickInterlaceOptions,
4116       MagickFalse,option);
4117   option=GetImageOption(image_info,"interpolate");
4118   if (option != (const char *) NULL)
4119     image->interpolate=(PixelInterpolateMethod) ParseCommandOption(
4120       MagickInterpolateOptions,MagickFalse,option);
4121   option=GetImageOption(image_info,"loop");
4122   if (option != (const char *) NULL)
4123     image->iterations=StringToUnsignedLong(option);
4124   option=GetImageOption(image_info,"mattecolor");
4125   if (option != (const char *) NULL)
4126     (void) QueryColorCompliance(option,AllCompliance,&image->matte_color,
4127       exception);
4128   option=GetImageOption(image_info,"orient");
4129   if (option != (const char *) NULL)
4130     image->orientation=(OrientationType) ParseCommandOption(
4131       MagickOrientationOptions,MagickFalse,option);
4132   option=GetImageOption(image_info,"page");
4133   if (option != (const char *) NULL)
4134     {
4135       char
4136         *geometry;
4137 
4138       geometry=GetPageGeometry(option);
4139       flags=ParseAbsoluteGeometry(geometry,&image->page);
4140       geometry=DestroyString(geometry);
4141     }
4142   option=GetImageOption(image_info,"quality");
4143   if (option != (const char *) NULL)
4144     image->quality=StringToUnsignedLong(option);
4145   option=GetImageOption(image_info,"red-primary");
4146   if (option != (const char *) NULL)
4147     {
4148       flags=ParseGeometry(option,&geometry_info);
4149       image->chromaticity.red_primary.x=geometry_info.rho;
4150       image->chromaticity.red_primary.y=geometry_info.sigma;
4151       if ((flags & SigmaValue) == 0)
4152         image->chromaticity.red_primary.y=image->chromaticity.red_primary.x;
4153     }
4154   if (image_info->quality != UndefinedCompressionQuality)
4155     image->quality=image_info->quality;
4156   option=GetImageOption(image_info,"scene");
4157   if (option != (const char *) NULL)
4158     image->scene=StringToUnsignedLong(option);
4159   option=GetImageOption(image_info,"taint");
4160   if (option != (const char *) NULL)
4161     image->taint=(MagickBooleanType) ParseCommandOption(MagickBooleanOptions,
4162       MagickFalse,option);
4163   option=GetImageOption(image_info,"tile-offset");
4164   if (option != (const char *) NULL)
4165     {
4166       char
4167         *geometry;
4168 
4169       geometry=GetPageGeometry(option);
4170       flags=ParseAbsoluteGeometry(geometry,&image->tile_offset);
4171       geometry=DestroyString(geometry);
4172     }
4173   option=GetImageOption(image_info,"transparent-color");
4174   if (option != (const char *) NULL)
4175     (void) QueryColorCompliance(option,AllCompliance,&image->transparent_color,
4176       exception);
4177   option=GetImageOption(image_info,"type");
4178   if (option != (const char *) NULL)
4179     image->type=(ImageType) ParseCommandOption(MagickTypeOptions,MagickFalse,
4180       option);
4181   option=GetImageOption(image_info,"units");
4182   units=image_info->units;
4183   if (option != (const char *) NULL)
4184     units=(ResolutionType) ParseCommandOption(MagickResolutionOptions,
4185       MagickFalse,option);
4186   if (units != UndefinedResolution)
4187     {
4188       if (image->units != units)
4189         switch (image->units)
4190         {
4191           case PixelsPerInchResolution:
4192           {
4193             if (units == PixelsPerCentimeterResolution)
4194               {
4195                 image->resolution.x/=2.54;
4196                 image->resolution.y/=2.54;
4197               }
4198             break;
4199           }
4200           case PixelsPerCentimeterResolution:
4201           {
4202             if (units == PixelsPerInchResolution)
4203               {
4204                 image->resolution.x=(double) ((size_t) (100.0*2.54*
4205                   image->resolution.x+0.5))/100.0;
4206                 image->resolution.y=(double) ((size_t) (100.0*2.54*
4207                   image->resolution.y+0.5))/100.0;
4208               }
4209             break;
4210           }
4211           default:
4212             break;
4213         }
4214       image->units=units;
4215       option=GetImageOption(image_info,"density");
4216       if (option != (const char *) NULL)
4217         {
4218           flags=ParseGeometry(option,&geometry_info);
4219           image->resolution.x=geometry_info.rho;
4220           image->resolution.y=geometry_info.sigma;
4221           if ((flags & SigmaValue) == 0)
4222             image->resolution.y=image->resolution.x;
4223         }
4224     }
4225   option=GetImageOption(image_info,"virtual-pixel");
4226   if (option != (const char *) NULL)
4227     (void) SetImageVirtualPixelMethod(image,(VirtualPixelMethod)
4228       ParseCommandOption(MagickVirtualPixelOptions,MagickFalse,option),
4229       exception);
4230   option=GetImageOption(image_info,"white-point");
4231   if (option != (const char *) NULL)
4232     {
4233       flags=ParseGeometry(option,&geometry_info);
4234       image->chromaticity.white_point.x=geometry_info.rho;
4235       image->chromaticity.white_point.y=geometry_info.sigma;
4236       if ((flags & SigmaValue) == 0)
4237         image->chromaticity.white_point.y=image->chromaticity.white_point.x;
4238     }
4239   /*
4240     Pointer to allow the lookup of pre-image artifact will fallback to a global
4241     option setting/define.  This saves a lot of duplication of global options
4242     into per-image artifacts, while ensuring only specifically set per-image
4243     artifacts are preserved when parenthesis ends.
4244   */
4245   if (image->image_info != (ImageInfo *) NULL)
4246     image->image_info=DestroyImageInfo(image->image_info);
4247   image->image_info=CloneImageInfo(image_info);
4248   return(MagickTrue);
4249 }
4250