source: ImageMagick/branches/ImageMagick-6/magick/image.c @ 8254

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