root / ImageMagick / trunk / magick / constitute.c

Revision 12615, 45.9 kB (checked in by cristy, 4 days ago)
Line 
1/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3%                                                                             %
4%                                                                             %
5%                                                                             %
6%     CCCC   OOO   N   N  SSSSS  TTTTT  IIIII  TTTTT  U   U  TTTTT  EEEEE     %
7%    C      O   O  NN  N  SS       T      I      T    U   U    T    E         %
8%    C      O   O  N N N  ESSS     T      I      T    U   U    T    EEE       %
9%    C      O   O  N  NN     SS    T      I      T    U   U    T    E         %
10%     CCCC   OOO   N   N  SSSSS    T    IIIII    T     UUU     T    EEEEE     %
11%                                                                             %
12%                                                                             %
13%                       Methods to Consitute an Image                         %
14%                                                                             %
15%                             Software Design                                 %
16%                               John Cristy                                   %
17%                               October 1998                                  %
18%                                                                             %
19%                                                                             %
20%  Copyright 1999-2008 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  Include declarations.
41*/
42#include "magick/studio.h"
43#include "magick/blob.h"
44#include "magick/blob-private.h"
45#include "magick/exception.h"
46#include "magick/exception-private.h"
47#include "magick/cache.h"
48#include "magick/client.h"
49#include "magick/constitute.h"
50#include "magick/delegate.h"
51#include "magick/geometry.h"
52#include "magick/identify.h"
53#include "magick/image-private.h"
54#include "magick/list.h"
55#include "magick/magick.h"
56#include "magick/memory_.h"
57#include "magick/monitor.h"
58#include "magick/option.h"
59#include "magick/pixel.h"
60#include "magick/profile.h"
61#include "magick/property.h"
62#include "magick/quantum.h"
63#include "magick/resize.h"
64#include "magick/resource_.h"
65#include "magick/semaphore.h"
66#include "magick/statistic.h"
67#include "magick/stream.h"
68#include "magick/string_.h"
69#include "magick/timer.h"
70#include "magick/transform.h"
71#include "magick/utility.h"
72
73static SemaphoreInfo
74  *constitute_semaphore = (SemaphoreInfo *) NULL;
75
76/*
77%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
78%                                                                             %
79%                                                                             %
80%                                                                             %
81%   C o n s t i t u t e I m a g e                                             %
82%                                                                             %
83%                                                                             %
84%                                                                             %
85%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
86%
87%  ConstituteImage() returns an image from the pixel data you supply.
88%  The pixel data must be in scanline order top-to-bottom.  The data can be
89%  char, short int, int, float, or double.  Float and double require the
90%  pixels to be normalized [0..1], otherwise [0..QuantumRange].  For example, to
91%  create a 640x480 image from unsigned red-green-blue character data, use:
92%
93%      image = ConstituteImage(640,480,"RGB",CharPixel,pixels,&exception);
94%
95%  The format of the ConstituteImage method is:
96%
97%      Image *ConstituteImage(const unsigned long columns,
98%        const unsigned long rows,const char *map,const StorageType storage,
99%        const void *pixels,ExceptionInfo *exception)
100%
101%  A description of each parameter follows:
102%
103%    o columns: width in pixels of the image.
104%
105%    o rows: height in pixels of the image.
106%
107%    o map:  This string reflects the expected ordering of the pixel array.
108%      It can be any combination or order of R = red, G = green, B = blue,
109%      A = alpha (0 is transparent), O = opacity (0 is opaque), C = cyan,
110%      Y = yellow, M = magenta, K = black, I = intensity (for grayscale),
111%      P = pad.
112%
113%    o storage: Define the data type of the pixels.  Float and double types are
114%      expected to be normalized [0..1] otherwise [0..QuantumRange].  Choose
115%      from these types: CharPixel, DoublePixel, FloatPixel, IntegerPixel,
116%      LongPixel, QuantumPixel, or ShortPixel.
117%
118%    o pixels: This array of values contain the pixel components as defined by
119%      map and type.  You must preallocate this array where the expected
120%      length varies depending on the values of width, height, map, and type.
121%
122%    o exception: Return any errors or warnings in this structure.
123%
124*/
125MagickExport Image *ConstituteImage(const unsigned long columns,
126  const unsigned long rows,const char *map,const StorageType storage,
127  const void *pixels,ExceptionInfo *exception)
128{
129  Image
130    *image;
131
132  MagickBooleanType
133    status;
134
135  /*
136    Allocate image structure.
137  */
138  assert(map != (const char *) NULL);
139  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",map);
140  assert(pixels != (void *) NULL);
141  assert(exception != (ExceptionInfo *) NULL);
142  assert(exception->signature == MagickSignature);
143  image=AcquireImage((ImageInfo *) NULL);
144  if (image == (Image *) NULL)
145    return((Image *) NULL);
146  if ((columns == 0) || (rows == 0))
147    ThrowImageException(OptionError,"NonZeroWidthAndHeightRequired");
148  image->columns=columns;
149  image->rows=rows;
150  (void) SetImageBackgroundColor(image);
151  status=ImportImagePixels(image,0,0,columns,rows,map,storage,pixels);
152  if (status == MagickFalse)
153    {
154      InheritException(exception,&image->exception);
155      image=DestroyImage(image);
156    }
157  return(image);
158}
159
160/*
161%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
162%                                                                             %
163%                                                                             %
164%                                                                             %
165+   D e s t r o y C o n s t i t u t e                                         %
166%                                                                             %
167%                                                                             %
168%                                                                             %
169%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
170%
171%  DestroyConstitute() destroys the constitute environment.
172%
173%  The format of the DestroyConstitute method is:
174%
175%      DestroyConstitute(void)
176%
177*/
178MagickExport void DestroyConstitute(void)
179{
180  if (constitute_semaphore != (SemaphoreInfo *) NULL)
181    DestroySemaphoreInfo(&constitute_semaphore);
182}
183
184/*
185%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
186%                                                                             %
187%                                                                             %
188%                                                                             %
189%   P i n g I m a g e                                                         %
190%                                                                             %
191%                                                                             %
192%                                                                             %
193%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
194%
195%  PingImage() returns all the properties of an image or image sequence
196%  except for the pixels.  It is much faster and consumes far less memory
197%  than ReadImage().  On failure, a NULL image is returned and exception
198%  describes the reason for the failure.
199%
200%  The format of the PingImage method is:
201%
202%      Image *PingImage(const ImageInfo *image_info,ExceptionInfo *exception)
203%
204%  A description of each parameter follows:
205%
206%    o image_info: Ping the image defined by the file or filename members of
207%      this structure.
208%
209%    o exception: Return any errors or warnings in this structure.
210%
211*/
212
213#if defined(__cplusplus) || defined(c_plusplus)
214extern "C" {
215#endif
216
217static size_t PingStream(const Image *magick_unused(image),
218  const void *magick_unused(pixels),const size_t columns)
219{
220  return(columns);
221}
222
223#if defined(__cplusplus) || defined(c_plusplus)
224}
225#endif
226
227MagickExport Image *PingImage(const ImageInfo *image_info,
228  ExceptionInfo *exception)
229{
230  Image
231    *image;
232
233  ImageInfo
234    *ping_info;
235
236  assert(image_info != (ImageInfo *) NULL);
237  assert(image_info->signature == MagickSignature);
238  if (image_info->debug != MagickFalse)
239    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
240      image_info->filename);
241  assert(exception != (ExceptionInfo *) NULL);
242  ping_info=CloneImageInfo(image_info);
243  ping_info->ping=MagickTrue;
244  image=ReadStream(ping_info,&PingStream,exception);
245  if (image != (Image *) NULL)
246    {
247      ResetTimer(&image->timer);
248      if (ping_info->verbose != MagickFalse)
249        (void) IdentifyImage(image,stdout,MagickFalse);
250    }
251  ping_info=DestroyImageInfo(ping_info);
252  return(image);
253}
254
255/*
256%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
257%                                                                             %
258%                                                                             %
259%                                                                             %
260%   P i n g I m a g e s                                                       %
261%                                                                             %
262%                                                                             %
263%                                                                             %
264%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
265%
266%  PingImages() pings one or more images and returns them as an image list.
267%
268%  The format of the PingImage method is:
269%
270%      Image *PingImages(const ImageInfo *image_info,ExceptionInfo *exception)
271%
272%  A description of each parameter follows:
273%
274%    o image_info: the image info.
275%
276%    o exception: Return any errors or warnings in this structure.
277%
278*/
279MagickExport Image *PingImages(const ImageInfo *image_info,
280  ExceptionInfo *exception)
281{
282  char
283    filename[MaxTextExtent];
284
285  Image
286    *image,
287    *images;
288
289  ImageInfo
290    *read_info;
291
292  /*
293    Ping image list from a file.
294  */
295  assert(image_info != (ImageInfo *) NULL);
296  assert(image_info->signature == MagickSignature);
297  if (image_info->debug != MagickFalse)
298    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
299      image_info->filename);
300  assert(exception != (ExceptionInfo *) NULL);
301  if (*image_info->filename == '@')
302    {
303      char
304        *command,
305        **image_list;
306
307      int
308        number_image_list;
309
310      register long
311        i;
312
313      /*
314        A file with a list of image filenames to read.
315      */
316      command=FileToString(image_info->filename+1,~0,exception);
317      if (command == (char *) NULL)
318        return((Image *) NULL);
319      StripString(command);
320      image_list=StringToArgv(command,&number_image_list);
321      command=DestroyString(command);
322      read_info=CloneImageInfo(image_info);
323      images=NewImageList();
324      for (i=1; i < number_image_list; i++)
325      {
326        (void) CopyMagickString(read_info->filename,image_list[i],
327          MaxTextExtent);
328        image=PingImage(read_info,exception);
329        if (image == (Image *) NULL)
330          continue;
331        AppendImageToList(&images,image);
332      }
333      read_info=DestroyImageInfo(read_info);
334      for (i=1; i < number_image_list; i++)
335        image_list[i]=DestroyString(image_list[i]);
336      image_list=(char **) RelinquishMagickMemory(image_list);
337      return(images);
338    }
339  (void) InterpretImageFilename(filename,MaxTextExtent,image_info->filename,
340    (int) image_info->scene);
341  if (LocaleCompare(filename,image_info->filename) != 0)
342    {
343      ExceptionInfo
344        *sans;
345
346      long
347        extent,
348        scene;
349
350      /*
351        Images of the form image-%d.png[1-5].
352      */
353      read_info=CloneImageInfo(image_info);
354      sans=AcquireExceptionInfo();
355      (void) SetImageInfo(read_info,MagickFalse,sans);
356      sans=DestroyExceptionInfo(sans);
357      (void) CopyMagickString(filename,read_info->filename,MaxTextExtent);
358      images=NewImageList();
359      extent=(long) (read_info->scene+read_info->number_scenes);
360      for (scene=read_info->scene; scene < (long) extent; scene++)
361      {
362        (void) InterpretImageFilename(read_info->filename,MaxTextExtent,
363          filename,(int) scene);
364        image=PingImage(read_info,exception);
365        if (image == (Image *) NULL)
366          continue;
367        AppendImageToList(&images,image);
368      }
369      read_info=DestroyImageInfo(read_info);
370      return(images);
371    }
372  return(PingImage(image_info,exception));
373}
374
375/*
376%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
377%                                                                             %
378%                                                                             %
379%                                                                             %
380%   R e a d I m a g e                                                         %
381%                                                                             %
382%                                                                             %
383%                                                                             %
384%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
385%
386%  ReadImage() reads an image or image sequence from a file or file handle.
387%  The method returns a NULL if there is a memory shortage or if the image
388%  cannot be read.  On failure, a NULL image is returned and exception
389%  describes the reason for the failure.
390%
391%  The format of the ReadImage method is:
392%
393%      Image *ReadImage(const ImageInfo *image_info,ExceptionInfo *exception)
394%
395%  A description of each parameter follows:
396%
397%    o image_info: Read the image defined by the file or filename members of
398%      this structure.
399%
400%    o exception: Return any errors or warnings in this structure.
401%
402*/
403MagickExport Image *ReadImage(const ImageInfo *image_info,
404  ExceptionInfo *exception)
405{
406  char
407    filename[MaxTextExtent],
408    magick[MaxTextExtent],
409    magick_filename[MaxTextExtent];
410
411  const char
412    *value;
413
414  const DelegateInfo
415    *delegate_info;
416
417  const MagickInfo
418    *magick_info;
419
420  ExceptionInfo
421    sans_exception;
422
423  GeometryInfo
424    geometry_info;
425
426  Image
427    *image,
428    *next;
429
430  ImageInfo
431    *read_info;
432
433  MagickStatusType
434    flags;
435
436  /*
437    Determine image type from filename prefix or suffix (e.g. image.jpg).
438  */
439  assert(image_info != (ImageInfo *) NULL);
440  assert(image_info->signature == MagickSignature);
441  assert(image_info->filename != (char *) NULL);
442  if (image_info->debug != MagickFalse)
443    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
444      image_info->filename);
445  assert(exception != (ExceptionInfo *) NULL);
446  read_info=CloneImageInfo(image_info);
447  (void) CopyMagickString(magick_filename,read_info->filename,MaxTextExtent);
448  (void) SetImageInfo(read_info,MagickFalse,exception);
449  (void) CopyMagickString(filename,read_info->filename,MaxTextExtent);
450  (void) CopyMagickString(magick,read_info->magick,MaxTextExtent);
451  /*
452    Call appropriate image reader based on image type.
453  */
454  GetExceptionInfo(&sans_exception);
455  magick_info=GetMagickInfo(read_info->magick,&sans_exception);
456  if (magick_info != (const MagickInfo *) NULL)
457    {
458      if (GetMagickEndianSupport(magick_info) == MagickFalse)
459        read_info->endian=UndefinedEndian;
460      else
461        if ((image_info->endian == UndefinedEndian) &&
462            (GetMagickRawSupport(magick_info) != MagickFalse))
463          {
464            unsigned long
465              lsb_first;
466 
467            lsb_first=1;
468            read_info->endian=(*(char *) &lsb_first) == 1 ? LSBEndian :
469              MSBEndian;
470         }
471    }
472  (void) DestroyExceptionInfo(&sans_exception);
473  if ((magick_info != (const MagickInfo *) NULL) &&
474      (GetMagickSeekableStream(magick_info) != MagickFalse))
475    {
476      MagickBooleanType
477        status;
478
479      image=AcquireImage(read_info);
480      (void) CopyMagickString(image->filename,read_info->filename,
481        MaxTextExtent);
482      status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
483      if (status == MagickFalse)
484        {
485          read_info=DestroyImageInfo(read_info);
486          image=DestroyImage(image);
487          return((Image *) NULL);
488        }
489      if (IsBlobSeekable(image) == MagickFalse)
490        {
491          /*
492            Coder requires a seekable stream.
493          */
494          *read_info->filename='\0';
495          status=ImageToFile(image,read_info->filename,exception);
496          if (status == MagickFalse)
497            {
498              (void) CloseBlob(image);
499              read_info=DestroyImageInfo(read_info);
500              image=DestroyImage(image);
501              return((Image *) NULL);
502            }
503          read_info->temporary=MagickTrue;
504        }
505      (void) CloseBlob(image);
506      image=DestroyImage(image);
507    }
508  image=NewImageList();
509  if ((magick_info != (const MagickInfo *) NULL) &&
510      (GetImageDecoder(magick_info) != (DecodeImageHandler *) NULL))
511    {
512      if ((GetMagickThreadSupport(magick_info) & DecoderThreadSupport) == 0)
513        AcquireSemaphoreInfo(&constitute_semaphore);
514      image=GetImageDecoder(magick_info)(read_info,exception);
515      if ((GetMagickThreadSupport(magick_info) & DecoderThreadSupport) == 0)
516        RelinquishSemaphoreInfo(constitute_semaphore);
517    }
518  else
519    {
520      delegate_info=GetDelegateInfo(read_info->magick,(char *) NULL,exception);
521      if (delegate_info == (const DelegateInfo *) NULL)
522        {
523          if (IsPathAccessible(read_info->filename) != MagickFalse)
524            (void) ThrowMagickException(exception,GetMagickModule(),
525              MissingDelegateError,"NoDecodeDelegateForThisImageFormat","`%s'",
526              read_info->filename);
527          if (read_info->temporary != MagickFalse)
528            (void) RelinquishUniqueFileResource(read_info->filename);
529          read_info=DestroyImageInfo(read_info);
530          return((Image *) NULL);
531        }
532      /*
533        Let our decoding delegate process the image.
534      */
535      image=AcquireImage(read_info);
536      if (image == (Image *) NULL)
537        {
538          read_info=DestroyImageInfo(read_info);
539          return((Image *) NULL);
540        }
541      (void) CopyMagickString(image->filename,read_info->filename,
542        MaxTextExtent);
543      *read_info->filename='\0';
544      if (GetDelegateThreadSupport(delegate_info) == MagickFalse)
545        AcquireSemaphoreInfo(&constitute_semaphore);
546      (void) InvokeDelegate(read_info,image,read_info->magick,(char *) NULL,
547        exception);
548      if (GetDelegateThreadSupport(delegate_info) == MagickFalse)
549        RelinquishSemaphoreInfo(constitute_semaphore);
550      image=DestroyImageList(image);
551      read_info->temporary=MagickTrue;
552      (void) SetImageInfo(read_info,MagickFalse,exception);
553      magick_info=GetMagickInfo(read_info->magick,exception);
554      if ((magick_info == (const MagickInfo *) NULL) ||
555          (GetImageDecoder(magick_info) == (DecodeImageHandler *) NULL))
556        {
557          if (IsPathAccessible(read_info->filename) != MagickFalse)
558            (void) ThrowMagickException(exception,GetMagickModule(),
559              MissingDelegateError,"NoDecodeDelegateForThisImageFormat","`%s'",
560              read_info->filename);
561          else
562            ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
563              read_info->filename);
564          read_info=DestroyImageInfo(read_info);
565          return((Image *) NULL);
566        }
567      if ((GetMagickThreadSupport(magick_info) & DecoderThreadSupport) == 0)
568        AcquireSemaphoreInfo(&constitute_semaphore);
569      image=(Image *) (GetImageDecoder(magick_info))(read_info,exception);
570      if ((GetMagickThreadSupport(magick_info) & DecoderThreadSupport) == 0)
571        RelinquishSemaphoreInfo(constitute_semaphore);
572    }
573  if (read_info->temporary != MagickFalse)
574    {
575      (void) RelinquishUniqueFileResource(read_info->filename);
576      read_info->temporary=MagickFalse;
577      if (image != (Image *) NULL)
578        (void) CopyMagickString(image->filename,filename,MaxTextExtent);
579    }
580  if (image == (Image *) NULL)
581    {
582      read_info=DestroyImageInfo(read_info);
583      return(image);
584    }
585  if (exception->severity >= ErrorException)
586    (void) LogMagickEvent(ExceptionEvent,GetMagickModule(),
587      "Coder (%s) generated an image despite an error (%d), "
588      "notify the developers",image->magick,exception->severity);
589  if (IsBlobTemporary(image) != MagickFalse)
590    (void) RelinquishUniqueFileResource(read_info->filename);
591  if ((GetNextImageInList(image) != (Image *) NULL) &&
592      (IsSceneGeometry(read_info->scenes,MagickFalse) != MagickFalse))
593    {
594      Image
595        *clones;
596
597      clones=CloneImages(image,read_info->scenes,exception);
598      if (clones == (Image *) NULL)
599        (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
600          "SubimageSpecificationReturnsNoImages","`%s'",read_info->filename);
601      else
602        {
603          image=DestroyImageList(image);
604          image=GetFirstImageInList(clones);
605        }
606    }
607  if (GetBlobError(image) != MagickFalse)
608    {
609      ThrowFileException(exception,FileOpenError,
610        "AnErrorHasOccurredReadingFromFile",read_info->filename);
611      image=DestroyImageList(image);
612      read_info=DestroyImageInfo(read_info);
613      return((Image *) NULL);
614    }
615  for (next=image; next != (Image *) NULL; next=GetNextImageInList(next))
616  {
617    char
618      timestamp[MaxTextExtent];
619
620    const StringInfo
621      *profile;
622
623    next->taint=MagickFalse;
624    if (next->magick_columns == 0)
625      next->magick_columns=next->columns;
626    if (next->magick_rows == 0)
627      next->magick_rows=next->rows;
628    if ((LocaleCompare(magick,"HTTP") != 0) &&
629        (LocaleCompare(magick,"FTP") != 0))
630      (void) CopyMagickString(next->magick,magick,MaxTextExtent);
631    (void) CopyMagickString(next->magick_filename,magick_filename,
632      MaxTextExtent);
633    if (IsBlobTemporary(image) != MagickFalse)
634      (void) CopyMagickString(next->filename,filename,MaxTextExtent);
635    value=GetImageProperty(next,"exif:Orientation");
636    if (value != (char *) NULL)
637      {
638        next->orientation=(OrientationType) atol(value);
639        (void) DeleteImageProperty(next,"exif:Orientation");
640      }
641    value=GetImageProperty(next,"tiff:XResolution");
642    if (value == (char *) NULL)
643      value=GetImageProperty(next,"exif:XResolution");
644    if (value != (char *) NULL)
645      {
646        geometry_info.rho=next->x_resolution;
647        geometry_info.sigma=1.0;
648        flags=ParseGeometry(value,&geometry_info);
649        if (geometry_info.sigma != 0)
650          next->x_resolution=geometry_info.rho/geometry_info.sigma;
651        (void) DeleteImageProperty(next,"exif:XResolution");
652        (void) DeleteImageProperty(next,"tiff:XResolution");
653      }
654    value=GetImageProperty(next,"tiff:YResolution");
655    if (value == (char *) NULL)
656      value=GetImageProperty(next,"exif:YResolution");
657    if (value != (char *) NULL)
658      {
659        geometry_info.rho=next->y_resolution;
660        geometry_info.sigma=1.0;
661        flags=ParseGeometry(value,&geometry_info);
662        if (geometry_info.sigma != 0)
663          next->y_resolution=geometry_info.rho/geometry_info.sigma;
664        (void) DeleteImageProperty(next,"exif:YResolution");
665        (void) DeleteImageProperty(next,"tiff:YResolution");
666      }
667    value=GetImageProperty(next,"tiff:ResolutionUnit");
668    if (value == (char *) NULL)
669      value=GetImageProperty(next,"exif:ResolutionUnit");
670    if (value != (char *) NULL)
671      {
672        next->units=(ResolutionType) (atoi(value)-1);
673        (void) DeleteImageProperty(next,"exif:ResolutionUnit");
674        (void) DeleteImageProperty(next,"tiff:ResolutionUnit");
675      }
676    if (next->page.width == 0)
677      next->page.width=next->columns;
678    if (next->page.height == 0)
679      next->page.height=next->rows;
680    if (*read_info->filename != '\0')
681      {
682        const char
683          *option;
684
685        option=GetImageOption(read_info,"caption");
686        if (option != (const char *) NULL)
687          (void) SetImageProperty(next,"caption",InterpretImageProperties(
688            read_info,next,option));
689        option=GetImageOption(read_info,"comment");
690        if (option != (const char *) NULL)
691          (void) SetImageProperty(next,"comment",InterpretImageProperties(
692            read_info,next,option));
693        option=GetImageOption(read_info,"label");
694        if (option != (const char *) NULL)
695          (void) SetImageProperty(next,"label",InterpretImageProperties(
696            read_info,next,option));
697      }
698    if (LocaleCompare(next->magick,"TEXT") == 0)
699      (void) ParseAbsoluteGeometry("0x0+0+0",&next->page);
700    if ((read_info->extract != (char *) NULL) &&
701        (read_info->stream == (StreamHandler) NULL))
702      {
703        RectangleInfo
704          geometry;
705
706        flags=ParseAbsoluteGeometry(read_info->extract,&geometry);
707        if ((next->columns != geometry.width) ||
708            (next->rows != geometry.height))
709          {
710            if (((flags & XValue) != 0) || ((flags & YValue) != 0))
711              {
712                Image
713                  *crop_image;
714
715                crop_image=CropImage(next,&geometry,exception);
716                if (crop_image != (Image *) NULL)
717                  ReplaceImageInList(&next,crop_image);
718              }
719            else
720              if (((flags & WidthValue) != 0) || ((flags & HeightValue) != 0))
721                {
722                  Image
723                    *size_image;
724
725                  flags=ParseSizeGeometry(next,read_info->extract,&geometry);
726                  size_image=ResizeImage(next,geometry.width,geometry.height,
727                    next->filter,next->blur,exception);
728                  if (size_image != (Image *) NULL)
729                    ReplaceImageInList(&next,size_image);
730                }
731          }
732      }
733    profile=GetImageProfile(next,"icc");
734    if (profile == (const StringInfo *) NULL)
735      profile=GetImageProfile(next,"icm");
736    if (profile != (const StringInfo *) NULL)
737      {
738        next->color_profile.length=GetStringInfoLength(profile);
739        next->color_profile.info=GetStringInfoDatum(profile);
740      }
741    profile=GetImageProfile(next,"iptc");
742    if (profile == (const StringInfo *) NULL)
743      profile=GetImageProfile(next,"8bim");
744    if (profile != (const StringInfo *) NULL)
745      {
746        next->iptc_profile.length=GetStringInfoLength(profile);
747        next->iptc_profile.info=GetStringInfoDatum(profile);
748      }
749    (void) FormatMagickTime(GetBlobProperties(next)->st_mtime,MaxTextExtent,
750      timestamp);
751    (void) SetImageProperty(next,"modify-date",timestamp);
752    (void) FormatMagickTime(GetBlobProperties(next)->st_ctime,MaxTextExtent,
753      timestamp);
754    (void) SetImageProperty(next,"create-date",timestamp);
755    if (read_info->verbose != MagickFalse)
756      (void) IdentifyImage(next,stdout,MagickFalse);
757    image=next;
758  }
759  read_info=DestroyImageInfo(read_info);
760  return(GetFirstImageInList(image));
761}
762
763/*
764%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
765%                                                                             %
766%                                                                             %
767%                                                                             %
768%   R e a d I m a g e s                                                       %
769%                                                                             %
770%                                                                             %
771%                                                                             %
772%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
773%
774%  ReadImages() reads one or more images and returns them as an image list.
775%
776%  The format of the ReadImage method is:
777%
778%      Image *ReadImages(const ImageInfo *image_info,ExceptionInfo *exception)
779%
780%  A description of each parameter follows:
781%
782%    o image_info: the image info.
783%
784%    o exception: Return any errors or warnings in this structure.
785%
786*/
787MagickExport Image *ReadImages(const ImageInfo *image_info,
788  ExceptionInfo *exception)
789{
790  char
791    filename[MaxTextExtent];
792
793  Image
794    *image,
795    *images;
796
797  ImageInfo
798    *read_info;
799
800  /*
801    Read image list from a file.
802  */
803  assert(image_info != (ImageInfo *) NULL);
804  assert(image_info->signature == MagickSignature);
805  if (image_info->debug != MagickFalse)
806    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
807      image_info->filename);
808  assert(exception != (ExceptionInfo *) NULL);
809  if (*image_info->filename == '@')
810    {
811      char
812        *command,
813        **image_list;
814
815      int
816        number_image_list;
817
818      register long
819        i;
820
821      /*
822        A file with a list of image filenames to read.
823      */
824      command=FileToString(image_info->filename+1,~0,exception);
825      if (command == (char *) NULL)
826        return((Image *) NULL);
827      StripString(command);
828      image_list=StringToArgv(command,&number_image_list);
829      command=DestroyString(command);
830      read_info=CloneImageInfo(image_info);
831      images=NewImageList();
832      for (i=1; i < number_image_list; i++)
833      {
834        (void) CopyMagickString(read_info->filename,image_list[i],
835          MaxTextExtent);
836        image=ReadImage(read_info,exception);
837        if (image == (Image *) NULL)
838          continue;
839        AppendImageToList(&images,image);
840      }
841      read_info=DestroyImageInfo(read_info);
842      for (i=1; i < number_image_list; i++)
843        image_list[i]=DestroyString(image_list[i]);
844      image_list=(char **) RelinquishMagickMemory(image_list);
845      return(images);
846    }
847  (void) InterpretImageFilename(filename,MaxTextExtent,image_info->filename,
848    (int) image_info->scene);
849  if (LocaleCompare(filename,image_info->filename) != 0)
850    {
851      ExceptionInfo
852        *sans;
853
854      long
855        extent,
856        scene;
857
858      /*
859        Images of the form image-%d.png[1-5].
860      */
861      read_info=CloneImageInfo(image_info);
862      sans=AcquireExceptionInfo();
863      (void) SetImageInfo(read_info,MagickFalse,sans);
864      sans=DestroyExceptionInfo(sans);
865      (void) CopyMagickString(filename,read_info->filename,MaxTextExtent);
866      images=NewImageList();
867      extent=(long) (read_info->scene+read_info->number_scenes);
868      for (scene=read_info->scene; scene < (long) extent; scene++)
869      {
870        (void) InterpretImageFilename(read_info->filename,MaxTextExtent,
871          filename,(int) scene);
872        image=ReadImage(read_info,exception);
873        if (image == (Image *) NULL)
874          continue;
875        AppendImageToList(&images,image);
876      }
877      read_info=DestroyImageInfo(read_info);
878      return(images);
879    }
880  return(ReadImage(image_info,exception));
881}
882
883/*
884%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
885%                                                                             %
886%                                                                             %
887%                                                                             %
888+   R e a d I n l i n e I m a g e                                             %
889%                                                                             %
890%                                                                             %
891%                                                                             %
892%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
893%
894%  ReadInlineImage() reads a Base64-encoded inline image or image sequence.
895%  The method returns a NULL if there is a memory shortage or if the image
896%  cannot be read.  On failure, a NULL image is returned and exception
897%  describes the reason for the failure.
898%
899%  The format of the ReadInlineImage method is:
900%
901%      Image *ReadInlineImage(const ImageInfo *image_info,const char *content,
902%        ExceptionInfo *exception)
903%
904%  A description of each parameter follows:
905%
906%    o image_info: the image info.
907%
908%    o content: the image encoded in Base64.
909%
910%    o exception: Return any errors or warnings in this structure.
911%
912*/
913MagickExport Image *ReadInlineImage(const ImageInfo *image_info,
914  const char *content,ExceptionInfo *exception)
915{
916  Image
917    *image;
918
919  ImageInfo
920    *read_info;
921
922  unsigned char
923    *blob;
924
925  size_t
926    length;
927
928  register const char
929    *p;
930
931  image=NewImageList();
932  for (p=content; (*p != ',') && (*p != '\0'); p++) ;
933  if (*p == '\0')
934    ThrowReaderException(CorruptImageWarning,"CorruptImage");
935  p++;
936  length=0;
937  blob=Base64Decode(p,&length);
938  if (length == 0)
939    ThrowReaderException(CorruptImageWarning,"CorruptImage");
940  read_info=CloneImageInfo(image_info);
941  (void) SetImageInfoProgressMonitor(read_info,(MagickProgressMonitor) NULL,
942    (void *) NULL);
943  image=BlobToImage(read_info,blob,length,exception);
944  blob=(unsigned char *) RelinquishMagickMemory(blob);
945  read_info=DestroyImageInfo(read_info);
946  return(image);
947}
948
949/*
950%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
951%                                                                             %
952%                                                                             %
953%                                                                             %
954%   W r i t e I m a g e                                                       %
955%                                                                             %
956%                                                                             %
957%                                                                             %
958%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
959%
960%  WriteImage() writes an image or an image sequence to a file or filehandle.
961%  If writing to a file on disk, the name is defined by the filename member of
962%  the image structure.  Write() returns MagickFalse is these is a memo