root / ImageMagick / branches / ImageMagick-6.3.5 / magick / constitute.c

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