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