MagickCore  7.1.1-43
Convert, Edit, Or Compose Bitmap Images
constitute.c
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 % MagickCore Methods to Constitute an Image %
14 % %
15 % Software Design %
16 % Cristy %
17 % October 1998 %
18 % %
19 % %
20 % Copyright @ 1999 ImageMagick Studio LLC, a non-profit organization %
21 % dedicated to making software imaging solutions freely available. %
22 % %
23 % You may not use this file except in compliance with the License. You may %
24 % obtain a copy of the License at %
25 % %
26 % https://imagemagick.org/script/license.php %
27 % %
28 % Unless required by applicable law or agreed to in writing, software %
29 % distributed under the License is distributed on an "AS IS" BASIS, %
30 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31 % See the License for the specific language governing permissions and %
32 % limitations under the License. %
33 % %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35 %
36 %
37 */
38 
39 /*
40  Include declarations.
41 */
42 #include "MagickCore/studio.h"
43 #include "MagickCore/attribute.h"
44 #include "MagickCore/blob.h"
45 #include "MagickCore/blob-private.h"
46 #include "MagickCore/exception.h"
47 #include "MagickCore/exception-private.h"
48 #include "MagickCore/cache.h"
49 #include "MagickCore/client.h"
50 #include "MagickCore/coder-private.h"
51 #include "MagickCore/colorspace-private.h"
52 #include "MagickCore/constitute.h"
53 #include "MagickCore/constitute-private.h"
54 #include "MagickCore/delegate.h"
55 #include "MagickCore/geometry.h"
56 #include "MagickCore/identify.h"
57 #include "MagickCore/image-private.h"
58 #include "MagickCore/list.h"
59 #include "MagickCore/magick.h"
60 #include "MagickCore/memory_.h"
61 #include "MagickCore/monitor.h"
62 #include "MagickCore/monitor-private.h"
63 #include "MagickCore/option.h"
64 #include "MagickCore/pixel.h"
65 #include "MagickCore/pixel-accessor.h"
66 #include "MagickCore/policy.h"
67 #include "MagickCore/profile.h"
68 #include "MagickCore/profile-private.h"
69 #include "MagickCore/property.h"
70 #include "MagickCore/quantum.h"
71 #include "MagickCore/resize.h"
72 #include "MagickCore/resource_.h"
73 #include "MagickCore/semaphore.h"
74 #include "MagickCore/statistic.h"
75 #include "MagickCore/stream.h"
76 #include "MagickCore/string_.h"
77 #include "MagickCore/string-private.h"
78 #include "MagickCore/timer.h"
79 #include "MagickCore/timer-private.h"
80 #include "MagickCore/token.h"
81 #include "MagickCore/transform.h"
82 #include "MagickCore/utility.h"
83 #include "MagickCore/utility-private.h"
84 
85 /*
86  Define declarations.
87 */
88 #define MaxReadRecursionDepth 100
89 
90 /*
91  Typedef declarations.
92 */
93 typedef struct _ConstituteInfo
94 {
95  const char
96  *caption,
97  *comment,
98  *dispose,
99  *label;
100 
101  MagickBooleanType
102  sync_from_exif,
103  sync_from_tiff;
104 
105  MagickStatusType
106  delay_flags;
107 
108  size_t
109  delay;
110 
111  ssize_t
112  ticks_per_second;
114 
115 /*
116 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
117 % %
118 % %
119 % %
120 % C o n s t i t u t e I m a g e %
121 % %
122 % %
123 % %
124 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
125 %
126 % ConstituteImage() returns an image from the pixel data you supply.
127 % The pixel data must be in scanline order top-to-bottom. The data can be
128 % char, short int, int, float, or double. Float and double require the
129 % pixels to be normalized [0..1], otherwise [0..QuantumRange]. For example, to
130 % create a 640x480 image from unsigned red-green-blue character data, use:
131 %
132 % image = ConstituteImage(640,480,"RGB",CharPixel,pixels,&exception);
133 %
134 % The format of the ConstituteImage method is:
135 %
136 % Image *ConstituteImage(const size_t columns,const size_t rows,
137 % const char *map,const StorageType storage,const void *pixels,
138 % ExceptionInfo *exception)
139 %
140 % A description of each parameter follows:
141 %
142 % o columns: width in pixels of the image.
143 %
144 % o rows: height in pixels of the image.
145 %
146 % o map: This string reflects the expected ordering of the pixel array.
147 % It can be any combination or order of R = red, G = green, B = blue,
148 % A = alpha (0 is transparent), O = opacity (0 is opaque), C = cyan,
149 % Y = yellow, M = magenta, K = black, I = intensity (for grayscale),
150 % P = pad.
151 %
152 % o storage: Define the data type of the pixels. Float and double types are
153 % expected to be normalized [0..1] otherwise [0..QuantumRange]. Choose
154 % from these types: CharPixel, DoublePixel, FloatPixel, IntegerPixel,
155 % LongPixel, QuantumPixel, or ShortPixel.
156 %
157 % o pixels: This array of values contain the pixel components as defined by
158 % map and type. You must preallocate this array where the expected
159 % length varies depending on the values of width, height, map, and type.
160 %
161 % o exception: return any errors or warnings in this structure.
162 %
163 */
164 MagickExport Image *ConstituteImage(const size_t columns,const size_t rows,
165  const char *map,const StorageType storage,const void *pixels,
166  ExceptionInfo *exception)
167 {
168  Image
169  *image;
170 
171  MagickBooleanType
172  status;
173 
174  ssize_t
175  i;
176 
177  size_t
178  length;
179 
180  /*
181  Allocate image structure.
182  */
183  assert(map != (const char *) NULL);
184  assert(pixels != (void *) NULL);
185  assert(exception != (ExceptionInfo *) NULL);
186  assert(exception->signature == MagickCoreSignature);
187  if (IsEventLogging() != MagickFalse)
188  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",map);
189  image=AcquireImage((ImageInfo *) NULL,exception);
190  if (image == (Image *) NULL)
191  return((Image *) NULL);
192  switch (storage)
193  {
194  case CharPixel: image->depth=8*sizeof(unsigned char); break;
195  case DoublePixel: image->depth=8*sizeof(double); break;
196  case FloatPixel: image->depth=8*sizeof(float); break;
197  case LongPixel: image->depth=8*sizeof(unsigned long); break;
198  case LongLongPixel: image->depth=8*sizeof(MagickSizeType); break;
199  case ShortPixel: image->depth=8*sizeof(unsigned short); break;
200  default: break;
201  }
202  length=strlen(map);
203  for (i=0; i < (ssize_t) length; i++)
204  {
205  switch (map[i])
206  {
207  case 'a':
208  case 'A':
209  case 'O':
210  case 'o':
211  {
212  image->alpha_trait=BlendPixelTrait;
213  break;
214  }
215  case 'C':
216  case 'c':
217  case 'm':
218  case 'M':
219  case 'Y':
220  case 'y':
221  case 'K':
222  case 'k':
223  {
224  image->colorspace=CMYKColorspace;
225  break;
226  }
227  case 'I':
228  case 'i':
229  {
230  image->colorspace=GRAYColorspace;
231  break;
232  }
233  default:
234  {
235  if (length == 1)
236  image->colorspace=GRAYColorspace;
237  break;
238  }
239  }
240  }
241  status=SetImageExtent(image,columns,rows,exception);
242  if (status == MagickFalse)
243  return(DestroyImageList(image));
244  status=ResetImagePixels(image,exception);
245  if (status == MagickFalse)
246  return(DestroyImageList(image));
247  status=ImportImagePixels(image,0,0,columns,rows,map,storage,pixels,exception);
248  if (status == MagickFalse)
249  image=DestroyImage(image);
250  return(image);
251 }
252 
253 /*
254 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
255 % %
256 % %
257 % %
258 % P i n g I m a g e %
259 % %
260 % %
261 % %
262 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
263 %
264 % PingImage() returns all the properties of an image or image sequence
265 % except for the pixels. It is much faster and consumes far less memory
266 % than ReadImage(). On failure, a NULL image is returned and exception
267 % describes the reason for the failure.
268 %
269 % The format of the PingImage method is:
270 %
271 % Image *PingImage(const ImageInfo *image_info,ExceptionInfo *exception)
272 %
273 % A description of each parameter follows:
274 %
275 % o image_info: Ping the image defined by the file or filename members of
276 % this structure.
277 %
278 % o exception: return any errors or warnings in this structure.
279 %
280 */
281 
282 #if defined(__cplusplus) || defined(c_plusplus)
283 extern "C" {
284 #endif
285 
286 static size_t PingStream(const Image *magick_unused(image),
287  const void *magick_unused(pixels),const size_t columns)
288 {
289  magick_unreferenced(image);
290  magick_unreferenced(pixels);
291  return(columns);
292 }
293 
294 #if defined(__cplusplus) || defined(c_plusplus)
295 }
296 #endif
297 
298 MagickExport Image *PingImage(const ImageInfo *image_info,
299  ExceptionInfo *exception)
300 {
301  Image
302  *image;
303 
304  ImageInfo
305  *ping_info;
306 
307  assert(image_info != (ImageInfo *) NULL);
308  assert(image_info->signature == MagickCoreSignature);
309  assert(exception != (ExceptionInfo *) NULL);
310  if (IsEventLogging() != MagickFalse)
311  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
312  image_info->filename);
313  ping_info=CloneImageInfo(image_info);
314  ping_info->ping=MagickTrue;
315  image=ReadStream(ping_info,&PingStream,exception);
316  if (image != (Image *) NULL)
317  {
318  ResetTimer(&image->timer);
319  if (ping_info->verbose != MagickFalse)
320  (void) IdentifyImage(image,stdout,MagickFalse,exception);
321  }
322  ping_info=DestroyImageInfo(ping_info);
323  return(image);
324 }
325 
326 /*
327 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
328 % %
329 % %
330 % %
331 % P i n g I m a g e s %
332 % %
333 % %
334 % %
335 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
336 %
337 % PingImages() pings one or more images and returns them as an image list.
338 %
339 % The format of the PingImage method is:
340 %
341 % Image *PingImages(ImageInfo *image_info,const char *filename,
342 % ExceptionInfo *exception)
343 %
344 % A description of each parameter follows:
345 %
346 % o image_info: the image info.
347 %
348 % o filename: the image filename.
349 %
350 % o exception: return any errors or warnings in this structure.
351 %
352 */
353 MagickExport Image *PingImages(ImageInfo *image_info,const char *filename,
354  ExceptionInfo *exception)
355 {
356  char
357  ping_filename[MagickPathExtent];
358 
359  Image
360  *image,
361  *images;
362 
363  ImageInfo
364  *read_info;
365 
366  /*
367  Ping image list from a file.
368  */
369  assert(image_info != (ImageInfo *) NULL);
370  assert(image_info->signature == MagickCoreSignature);
371  assert(exception != (ExceptionInfo *) NULL);
372  if (IsEventLogging() != MagickFalse)
373  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
374  image_info->filename);
375  (void) SetImageOption(image_info,"filename",filename);
376  (void) CopyMagickString(image_info->filename,filename,MagickPathExtent);
377  (void) InterpretImageFilename(image_info,(Image *) NULL,image_info->filename,
378  (int) image_info->scene,ping_filename,exception);
379  if (LocaleCompare(ping_filename,image_info->filename) != 0)
380  {
382  *sans;
383 
384  ssize_t
385  extent,
386  scene;
387 
388  /*
389  Images of the form image-%d.png[1-5].
390  */
391  read_info=CloneImageInfo(image_info);
392  sans=AcquireExceptionInfo();
393  (void) SetImageInfo(read_info,0,sans);
394  sans=DestroyExceptionInfo(sans);
395  if (read_info->number_scenes == 0)
396  {
397  read_info=DestroyImageInfo(read_info);
398  return(PingImage(image_info,exception));
399  }
400  (void) CopyMagickString(ping_filename,read_info->filename,
401  MagickPathExtent);
402  images=NewImageList();
403  extent=(ssize_t) (read_info->scene+read_info->number_scenes);
404  for (scene=(ssize_t) read_info->scene; scene < (ssize_t) extent; scene++)
405  {
406  (void) InterpretImageFilename(image_info,(Image *) NULL,ping_filename,
407  (int) scene,read_info->filename,exception);
408  image=PingImage(read_info,exception);
409  if (image == (Image *) NULL)
410  continue;
411  AppendImageToList(&images,image);
412  }
413  read_info=DestroyImageInfo(read_info);
414  return(images);
415  }
416  return(PingImage(image_info,exception));
417 }
418 
419 /*
420 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
421 % %
422 % %
423 % %
424 % R e a d I m a g e %
425 % %
426 % %
427 % %
428 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
429 %
430 % ReadImage() reads an image or image sequence from a file or file handle.
431 % The method returns a NULL if there is a memory shortage or if the image
432 % cannot be read. On failure, a NULL image is returned and exception
433 % describes the reason for the failure.
434 %
435 % The format of the ReadImage method is:
436 %
437 % Image *ReadImage(const ImageInfo *image_info,ExceptionInfo *exception)
438 %
439 % A description of each parameter follows:
440 %
441 % o image_info: Read the image defined by the file or filename members of
442 % this structure.
443 %
444 % o exception: return any errors or warnings in this structure.
445 %
446 */
447 
448 static MagickBooleanType IsCoderAuthorized(const char *coder,
449  const PolicyRights rights,ExceptionInfo *exception)
450 {
451  if (IsRightsAuthorized(CoderPolicyDomain,rights,coder) == MagickFalse)
452  {
453  errno=EPERM;
454  (void) ThrowMagickException(exception,GetMagickModule(),PolicyError,
455  "NotAuthorized","`%s'",coder);
456  return(MagickFalse);
457  }
458  return(MagickTrue);
459 }
460 
461 static void InitializeConstituteInfo(const ImageInfo *image_info,
462  ConstituteInfo *constitute_info)
463 {
464  const char
465  *option;
466 
467  memset(constitute_info,0,sizeof(*constitute_info));
468  constitute_info->sync_from_exif=MagickTrue;
469  constitute_info->sync_from_tiff=MagickTrue;
470  option=GetImageOption(image_info,"exif:sync-image");
471  if (IsStringFalse(option) != MagickFalse)
472  constitute_info->sync_from_exif=MagickFalse;
473  option=GetImageOption(image_info,"tiff:sync-image");
474  if (IsStringFalse(option) != MagickFalse)
475  constitute_info->sync_from_tiff=MagickFalse;
476  constitute_info->caption=GetImageOption(image_info,"caption");
477  constitute_info->comment=GetImageOption(image_info,"comment");
478  constitute_info->label=GetImageOption(image_info,"label");
479  option=GetImageOption(image_info,"delay");
480  if (option != (const char *) NULL)
481  {
483  geometry_info;
484 
485  constitute_info->delay_flags=ParseGeometry(option,&geometry_info);
486  if (constitute_info->delay_flags != NoValue)
487  {
488  constitute_info->delay=floor(geometry_info.rho+0.5);
489  if ((constitute_info->delay_flags & SigmaValue) != 0)
490  constitute_info->ticks_per_second=CastDoubleToLong(floor(
491  geometry_info.sigma+0.5));
492  }
493  }
494 }
495 
496 static void SyncOrientationFromProperties(Image *image,
497  ConstituteInfo *constitute_info,ExceptionInfo *exception)
498 {
499  const char
500  *orientation;
501 
502  orientation=(const char *) NULL;
503  if (constitute_info->sync_from_exif != MagickFalse)
504  {
505  orientation=GetImageProperty(image,"exif:Orientation",exception);
506  if (orientation != (const char *) NULL)
507  {
508  image->orientation=(OrientationType) StringToLong(orientation);
509  (void) DeleteImageProperty(image,"exif:Orientation");
510  }
511  }
512  if ((orientation == (const char *) NULL) &&
513  (constitute_info->sync_from_tiff != MagickFalse))
514  {
515  orientation=GetImageProperty(image,"tiff:Orientation",exception);
516  if (orientation != (const char *) NULL)
517  {
518  image->orientation=(OrientationType) StringToLong(orientation);
519  (void) DeleteImageProperty(image,"tiff:Orientation");
520  }
521  }
522 }
523 
524 static void SyncResolutionFromProperties(Image *image,
525  ConstituteInfo *constitute_info, ExceptionInfo *exception)
526 {
527  const char
528  *resolution_x,
529  *resolution_y,
530  *resolution_units;
531 
532  MagickBooleanType
533  used_tiff;
534 
535  resolution_x=(const char *) NULL;
536  resolution_y=(const char *) NULL;
537  resolution_units=(const char *) NULL;
538  used_tiff=MagickFalse;
539  if (constitute_info->sync_from_exif != MagickFalse)
540  {
541  resolution_x=GetImageProperty(image,"exif:XResolution",exception);
542  resolution_y=GetImageProperty(image,"exif:YResolution",exception);
543  if ((resolution_x != (const char *) NULL) &&
544  (resolution_y != (const char *) NULL))
545  resolution_units=GetImageProperty(image,"exif:ResolutionUnit",
546  exception);
547  }
548  if ((resolution_x == (const char *) NULL) &&
549  (resolution_y == (const char *) NULL) &&
550  (constitute_info->sync_from_tiff != MagickFalse))
551  {
552  resolution_x=GetImageProperty(image,"tiff:XResolution",exception);
553  resolution_y=GetImageProperty(image,"tiff:YResolution",exception);
554  if ((resolution_x != (const char *) NULL) &&
555  (resolution_y != (const char *) NULL))
556  {
557  used_tiff=MagickTrue;
558  resolution_units=GetImageProperty(image,"tiff:ResolutionUnit",
559  exception);
560  }
561  }
562  if ((resolution_x != (const char *) NULL) &&
563  (resolution_y != (const char *) NULL))
564  {
566  geometry_info;
567 
568  ssize_t
569  option_type;
570 
571  geometry_info.rho=image->resolution.x;
572  geometry_info.sigma=1.0;
573  (void) ParseGeometry(resolution_x,&geometry_info);
574  if (geometry_info.sigma != 0)
575  image->resolution.x=geometry_info.rho/geometry_info.sigma;
576  if (strchr(resolution_x,',') != (char *) NULL)
577  image->resolution.x=geometry_info.rho+geometry_info.sigma/1000.0;
578  geometry_info.rho=image->resolution.y;
579  geometry_info.sigma=1.0;
580  (void) ParseGeometry(resolution_y,&geometry_info);
581  if (geometry_info.sigma != 0)
582  image->resolution.y=geometry_info.rho/geometry_info.sigma;
583  if (strchr(resolution_y,',') != (char *) NULL)
584  image->resolution.y=geometry_info.rho+geometry_info.sigma/1000.0;
585  if (resolution_units != (char *) NULL)
586  {
587  option_type=ParseCommandOption(MagickResolutionOptions,MagickFalse,
588  resolution_units);
589  if (option_type >= 0)
590  image->units=(ResolutionType) option_type;
591  }
592  if (used_tiff == MagickFalse)
593  {
594  (void) DeleteImageProperty(image,"exif:XResolution");
595  (void) DeleteImageProperty(image,"exif:YResolution");
596  (void) DeleteImageProperty(image,"exif:ResolutionUnit");
597  }
598  else
599  {
600  (void) DeleteImageProperty(image,"tiff:XResolution");
601  (void) DeleteImageProperty(image,"tiff:YResolution");
602  (void) DeleteImageProperty(image,"tiff:ResolutionUnit");
603  }
604  }
605 }
606 
607 MagickExport Image *ReadImage(const ImageInfo *image_info,
608  ExceptionInfo *exception)
609 {
610  char
611  filename[MagickPathExtent],
612  magick[MagickPathExtent],
613  magick_filename[MagickPathExtent];
614 
616  constitute_info;
617 
618  const DelegateInfo
619  *delegate_info;
620 
621  const MagickInfo
622  *magick_info;
623 
624  DecodeImageHandler
625  *decoder;
626 
628  *sans_exception;
629 
630  Image
631  *image,
632  *next;
633 
634  ImageInfo
635  *read_info;
636 
637  MagickBooleanType
638  status;
639 
640  /*
641  Determine image type from filename prefix or suffix (e.g. image.jpg).
642  */
643  assert(image_info != (ImageInfo *) NULL);
644  assert(image_info->signature == MagickCoreSignature);
645  assert(image_info->filename != (char *) NULL);
646  if (IsEventLogging() != MagickFalse)
647  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
648  image_info->filename);
649  assert(exception != (ExceptionInfo *) NULL);
650  read_info=CloneImageInfo(image_info);
651  (void) CopyMagickString(magick_filename,read_info->filename,MagickPathExtent);
652  (void) SetImageInfo(read_info,0,exception);
653  (void) CopyMagickString(filename,read_info->filename,MagickPathExtent);
654  (void) CopyMagickString(magick,read_info->magick,MagickPathExtent);
655  /*
656  Call appropriate image reader based on image type.
657  */
658  sans_exception=AcquireExceptionInfo();
659  magick_info=GetMagickInfo(read_info->magick,sans_exception);
660  if (sans_exception->severity == PolicyError)
661  InheritException(exception,sans_exception);
662  sans_exception=DestroyExceptionInfo(sans_exception);
663  if (magick_info != (const MagickInfo *) NULL)
664  {
665  if (GetMagickEndianSupport(magick_info) == MagickFalse)
666  read_info->endian=UndefinedEndian;
667  else
668  if ((image_info->endian == UndefinedEndian) &&
669  (GetMagickRawSupport(magick_info) != MagickFalse))
670  {
671  unsigned long
672  lsb_first;
673 
674  lsb_first=1;
675  read_info->endian=(*(char *) &lsb_first) == 1 ? LSBEndian :
676  MSBEndian;
677  }
678  }
679  if ((magick_info != (const MagickInfo *) NULL) &&
680  (GetMagickDecoderSeekableStream(magick_info) != MagickFalse))
681  {
682  image=AcquireImage(read_info,exception);
683  (void) CopyMagickString(image->filename,read_info->filename,
684  MagickPathExtent);
685  status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
686  if (status == MagickFalse)
687  {
688  read_info=DestroyImageInfo(read_info);
689  image=DestroyImage(image);
690  return((Image *) NULL);
691  }
692  if (IsBlobSeekable(image) == MagickFalse)
693  {
694  /*
695  Coder requires a seekable stream.
696  */
697  *read_info->filename='\0';
698  status=ImageToFile(image,read_info->filename,exception);
699  if (status == MagickFalse)
700  {
701  (void) CloseBlob(image);
702  read_info=DestroyImageInfo(read_info);
703  image=DestroyImage(image);
704  return((Image *) NULL);
705  }
706  read_info->temporary=MagickTrue;
707  }
708  (void) CloseBlob(image);
709  image=DestroyImage(image);
710  }
711  image=NewImageList();
712  decoder=GetImageDecoder(magick_info);
713  if (decoder == (DecodeImageHandler *) NULL)
714  {
715  delegate_info=GetDelegateInfo(read_info->magick,(char *) NULL,exception);
716  if (delegate_info == (const DelegateInfo *) NULL)
717  {
718  (void) SetImageInfo(read_info,0,exception);
719  (void) CopyMagickString(read_info->filename,filename,
720  MagickPathExtent);
721  magick_info=GetMagickInfo(read_info->magick,exception);
722  decoder=GetImageDecoder(magick_info);
723  }
724  }
725  if (decoder != (DecodeImageHandler *) NULL)
726  {
727  /*
728  Call appropriate image reader based on image type.
729  */
730  if ((magick_info != (const MagickInfo *) NULL) &&
731  (GetMagickDecoderThreadSupport(magick_info) == MagickFalse))
732  LockSemaphoreInfo(magick_info->semaphore);
733  status=IsCoderAuthorized(read_info->magick,ReadPolicyRights,exception);
734  image=(Image *) NULL;
735  if (status != MagickFalse)
736  image=decoder(read_info,exception);
737  if ((magick_info != (const MagickInfo *) NULL) &&
738  (GetMagickDecoderThreadSupport(magick_info) == MagickFalse))
739  UnlockSemaphoreInfo(magick_info->semaphore);
740  }
741  else
742  {
743  delegate_info=GetDelegateInfo(read_info->magick,(char *) NULL,exception);
744  if (delegate_info == (const DelegateInfo *) NULL)
745  {
746  (void) ThrowMagickException(exception,GetMagickModule(),
747  MissingDelegateError,"NoDecodeDelegateForThisImageFormat","`%s'",
748  read_info->magick);
749  if (read_info->temporary != MagickFalse)
750  (void) RelinquishUniqueFileResource(read_info->filename);
751  read_info=DestroyImageInfo(read_info);
752  return((Image *) NULL);
753  }
754  /*
755  Let our decoding delegate process the image.
756  */
757  image=AcquireImage(read_info,exception);
758  if (image == (Image *) NULL)
759  {
760  read_info=DestroyImageInfo(read_info);
761  return((Image *) NULL);
762  }
763  (void) CopyMagickString(image->filename,read_info->filename,
764  MagickPathExtent);
765  *read_info->filename='\0';
766  if (GetDelegateThreadSupport(delegate_info) == MagickFalse)
767  LockSemaphoreInfo(delegate_info->semaphore);
768  status=InvokeDelegate(read_info,image,read_info->magick,(char *) NULL,
769  exception);
770  if (GetDelegateThreadSupport(delegate_info) == MagickFalse)
771  UnlockSemaphoreInfo(delegate_info->semaphore);
772  image=DestroyImageList(image);
773  read_info->temporary=MagickTrue;
774  if (status != MagickFalse)
775  (void) SetImageInfo(read_info,0,exception);
776  magick_info=GetMagickInfo(read_info->magick,exception);
777  decoder=GetImageDecoder(magick_info);
778  if (decoder == (DecodeImageHandler *) NULL)
779  {
780  if (IsPathAccessible(read_info->filename) != MagickFalse)
781  (void) ThrowMagickException(exception,GetMagickModule(),
782  MissingDelegateError,"NoDecodeDelegateForThisImageFormat","`%s'",
783  read_info->magick);
784  else
785  ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
786  read_info->filename);
787  read_info=DestroyImageInfo(read_info);
788  return((Image *) NULL);
789  }
790  /*
791  Call appropriate image reader based on image type.
792  */
793  if (GetMagickDecoderThreadSupport(magick_info) == MagickFalse)
794  LockSemaphoreInfo(magick_info->semaphore);
795  status=IsCoderAuthorized(read_info->magick,ReadPolicyRights,exception);
796  image=(Image *) NULL;
797  if (status != MagickFalse)
798  image=(decoder)(read_info,exception);
799  if (GetMagickDecoderThreadSupport(magick_info) == MagickFalse)
800  UnlockSemaphoreInfo(magick_info->semaphore);
801  }
802  if (read_info->temporary != MagickFalse)
803  {
804  (void) RelinquishUniqueFileResource(read_info->filename);
805  read_info->temporary=MagickFalse;
806  if (image != (Image *) NULL)
807  (void) CopyMagickString(image->filename,filename,MagickPathExtent);
808  }
809  if (image == (Image *) NULL)
810  {
811  read_info=DestroyImageInfo(read_info);
812  return(image);
813  }
814  if (exception->severity >= ErrorException)
815  (void) LogMagickEvent(ExceptionEvent,GetMagickModule(),
816  "Coder (%s) generated an image despite an error (%d), "
817  "notify the developers",image->magick,exception->severity);
818  if (IsBlobTemporary(image) != MagickFalse)
819  (void) RelinquishUniqueFileResource(read_info->filename);
820  if ((IsSceneGeometry(read_info->scenes,MagickFalse) != MagickFalse) &&
821  (GetImageListLength(image) != 1))
822  {
823  Image
824  *clones;
825 
826  clones=CloneImages(image,read_info->scenes,exception);
827  image=DestroyImageList(image);
828  if (clones != (Image *) NULL)
829  image=GetFirstImageInList(clones);
830  if (image == (Image *) NULL)
831  {
832  read_info=DestroyImageInfo(read_info);
833  return(image);
834  }
835  }
836  InitializeConstituteInfo(read_info,&constitute_info);
837  for (next=image; next != (Image *) NULL; next=GetNextImageInList(next))
838  {
839  char
840  magick_path[MagickPathExtent],
841  *property;
842 
843  const StringInfo
844  *profile;
845 
846  static const char
847  *source_date_epoch = (const char *) NULL;
848 
849  static MagickBooleanType
850  epoch_initialized = MagickFalse;
851 
852  next->taint=MagickFalse;
853  GetPathComponent(magick_filename,MagickPath,magick_path);
854  if ((*magick_path == '\0') && (*next->magick == '\0'))
855  (void) CopyMagickString(next->magick,magick,MagickPathExtent);
856  (void) CopyMagickString(next->magick_filename,magick_filename,
857  MagickPathExtent);
858  if (IsBlobTemporary(image) != MagickFalse)
859  (void) CopyMagickString(next->filename,filename,MagickPathExtent);
860  if (next->magick_columns == 0)
861  next->magick_columns=next->columns;
862  if (next->magick_rows == 0)
863  next->magick_rows=next->rows;
864  (void) GetImageProperty(next,"exif:*",exception);
865  (void) GetImageProperty(next,"icc:*",exception);
866  (void) GetImageProperty(next,"iptc:*",exception);
867  (void) GetImageProperty(next,"xmp:*",exception);
868  SyncOrientationFromProperties(next,&constitute_info,exception);
869  SyncResolutionFromProperties(next,&constitute_info,exception);
870  if (next->page.width == 0)
871  next->page.width=next->columns;
872  if (next->page.height == 0)
873  next->page.height=next->rows;
874  if (constitute_info.caption != (const char *) NULL)
875  {
876  property=InterpretImageProperties(read_info,next,
877  constitute_info.caption,exception);
878  (void) SetImageProperty(next,"caption",property,exception);
879  property=DestroyString(property);
880  }
881  if (constitute_info.comment != (const char *) NULL)
882  {
883  property=InterpretImageProperties(read_info,next,
884  constitute_info.comment,exception);
885  (void) SetImageProperty(next,"comment",property,exception);
886  property=DestroyString(property);
887  }
888  if (constitute_info.label != (const char *) NULL)
889  {
890  property=InterpretImageProperties(read_info,next,
891  constitute_info.label,exception);
892  (void) SetImageProperty(next,"label",property,exception);
893  property=DestroyString(property);
894  }
895  if (LocaleCompare(next->magick,"TEXT") == 0)
896  (void) ParseAbsoluteGeometry("0x0+0+0",&next->page);
897  if ((read_info->extract != (char *) NULL) &&
898  (read_info->stream == (StreamHandler) NULL))
899  {
901  geometry;
902 
903  MagickStatusType
904  flags;
905 
906  SetGeometry(next,&geometry);
907  flags=ParseAbsoluteGeometry(read_info->extract,&geometry);
908  if ((next->columns != geometry.width) ||
909  (next->rows != geometry.height))
910  {
911  if (((flags & XValue) != 0) || ((flags & YValue) != 0))
912  {
913  Image
914  *crop_image;
915 
916  crop_image=CropImage(next,&geometry,exception);
917  if (crop_image != (Image *) NULL)
918  ReplaceImageInList(&next,crop_image);
919  }
920  else
921  if (((flags & WidthValue) != 0) || ((flags & HeightValue) != 0))
922  {
923  flags=ParseRegionGeometry(next,read_info->extract,&geometry,
924  exception);
925  if ((geometry.width != 0) && (geometry.height != 0))
926  {
927  Image *resize_image = ResizeImage(next,geometry.width,
928  geometry.height,next->filter,exception);
929  if (resize_image != (Image *) NULL)
930  ReplaceImageInList(&next,resize_image);
931  }
932  }
933  }
934  }
935  profile=GetImageProfile(next,"icc");
936  if (profile == (const StringInfo *) NULL)
937  profile=GetImageProfile(next,"icm");
938  profile=GetImageProfile(next,"iptc");
939  if (profile == (const StringInfo *) NULL)
940  profile=GetImageProfile(next,"8bim");
941  if (epoch_initialized == MagickFalse)
942  {
943  source_date_epoch=getenv("SOURCE_DATE_EPOCH");
944  epoch_initialized=MagickTrue;
945  }
946  if (source_date_epoch == (const char *) NULL)
947  {
948  char
949  timestamp[MagickTimeExtent];
950 
951  (void) FormatMagickTime(next->timestamp,sizeof(timestamp),timestamp);
952  (void) SetImageProperty(next,"date:timestamp",timestamp,exception);
953  (void) FormatMagickTime((time_t) GetBlobProperties(next)->st_mtime,
954  sizeof(timestamp),timestamp);
955  (void) SetImageProperty(next,"date:modify",timestamp,exception);
956  (void) FormatMagickTime((time_t) GetBlobProperties(next)->st_ctime,
957  sizeof(timestamp),timestamp);
958  (void) SetImageProperty(next,"date:create",timestamp,exception);
959  }
960  if (constitute_info.delay_flags != NoValue)
961  {
962  if ((constitute_info.delay_flags & GreaterValue) != 0)
963  {
964  if (next->delay > constitute_info.delay)
965  next->delay=constitute_info.delay;
966  }
967  else
968  if ((constitute_info.delay_flags & LessValue) != 0)
969  {
970  if (next->delay < constitute_info.delay)
971  next->delay=constitute_info.delay;
972  }
973  else
974  next->delay=constitute_info.delay;
975  if ((constitute_info.delay_flags & SigmaValue) != 0)
976  next->ticks_per_second=constitute_info.ticks_per_second;
977  }
978  if (constitute_info.dispose != (const char *) NULL)
979  {
980  ssize_t
981  option_type;
982 
983  option_type=ParseCommandOption(MagickDisposeOptions,MagickFalse,
984  constitute_info.dispose);
985  if (option_type >= 0)
986  next->dispose=(DisposeType) option_type;
987  }
988  if (read_info->verbose != MagickFalse)
989  (void) IdentifyImage(next,stderr,MagickFalse,exception);
990  image=next;
991  }
992  read_info=DestroyImageInfo(read_info);
993  if (GetBlobError(image) != MagickFalse)
994  ThrowReaderException(CorruptImageError,"UnableToReadImageData");
995  return(GetFirstImageInList(image));
996 }
997 
998 /*
999 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1000 % %
1001 % %
1002 % %
1003 % R e a d I m a g e s %
1004 % %
1005 % %
1006 % %
1007 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1008 %
1009 % ReadImages() reads one or more images and returns them as an image list.
1010 %
1011 % The format of the ReadImage method is:
1012 %
1013 % Image *ReadImages(ImageInfo *image_info,const char *filename,
1014 % ExceptionInfo *exception)
1015 %
1016 % A description of each parameter follows:
1017 %
1018 % o image_info: the image info.
1019 %
1020 % o filename: the image filename.
1021 %
1022 % o exception: return any errors or warnings in this structure.
1023 %
1024 */
1025 MagickExport Image *ReadImages(ImageInfo *image_info,const char *filename,
1026  ExceptionInfo *exception)
1027 {
1028  char
1029  read_filename[MagickPathExtent];
1030 
1031  Image
1032  *image,
1033  *images;
1034 
1035  ImageInfo
1036  *read_info;
1037 
1038  /*
1039  Read image list from a file.
1040  */
1041  assert(image_info != (ImageInfo *) NULL);
1042  assert(image_info->signature == MagickCoreSignature);
1043  assert(exception != (ExceptionInfo *) NULL);
1044  if (IsEventLogging() != MagickFalse)
1045  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1046  image_info->filename);
1047  read_info=CloneImageInfo(image_info);
1048  *read_info->magick='\0';
1049  (void) SetImageOption(read_info,"filename",filename);
1050  (void) CopyMagickString(read_info->filename,filename,MagickPathExtent);
1051  (void) InterpretImageFilename(read_info,(Image *) NULL,filename,
1052  (int) read_info->scene,read_filename,exception);
1053  if (LocaleCompare(read_filename,read_info->filename) != 0)
1054  {
1056  *sans;
1057 
1058  ssize_t
1059  extent,
1060  scene;
1061 
1062  /*
1063  Images of the form image-%d.png[1-5].
1064  */
1065  sans=AcquireExceptionInfo();
1066  (void) SetImageInfo(read_info,0,sans);
1067  sans=DestroyExceptionInfo(sans);
1068  if (read_info->number_scenes != 0)
1069  {
1070  (void) CopyMagickString(read_filename,read_info->filename,
1071  MagickPathExtent);
1072  images=NewImageList();
1073  extent=(ssize_t) (read_info->scene+read_info->number_scenes);
1074  scene=(ssize_t) read_info->scene;
1075  for ( ; scene < (ssize_t) extent; scene++)
1076  {
1077  (void) InterpretImageFilename(image_info,(Image *) NULL,
1078  read_filename,(int) scene,read_info->filename,exception);
1079  image=ReadImage(read_info,exception);
1080  if (image == (Image *) NULL)
1081  continue;
1082  AppendImageToList(&images,image);
1083  }
1084  read_info=DestroyImageInfo(read_info);
1085  return(images);
1086  }
1087  }
1088  (void) CopyMagickString(read_info->filename,filename,MagickPathExtent);
1089  image=ReadImage(read_info,exception);
1090  read_info=DestroyImageInfo(read_info);
1091  return(image);
1092 }
1093 
1094 /*
1095 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1096 % %
1097 % %
1098 % %
1099 + R e a d I n l i n e I m a g e %
1100 % %
1101 % %
1102 % %
1103 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1104 %
1105 % ReadInlineImage() reads a Base64-encoded inline image or image sequence.
1106 % The method returns a NULL if there is a memory shortage or if the image
1107 % cannot be read. On failure, a NULL image is returned and exception
1108 % describes the reason for the failure.
1109 %
1110 % The format of the ReadInlineImage method is:
1111 %
1112 % Image *ReadInlineImage(const ImageInfo *image_info,const char *content,
1113 % ExceptionInfo *exception)
1114 %
1115 % A description of each parameter follows:
1116 %
1117 % o image_info: the image info.
1118 %
1119 % o content: the image encoded in Base64.
1120 %
1121 % o exception: return any errors or warnings in this structure.
1122 %
1123 */
1124 MagickExport Image *ReadInlineImage(const ImageInfo *image_info,
1125  const char *content,ExceptionInfo *exception)
1126 {
1127  Image
1128  *image;
1129 
1130  ImageInfo
1131  *read_info;
1132 
1133  unsigned char
1134  *blob;
1135 
1136  size_t
1137  length;
1138 
1139  const char
1140  *p;
1141 
1142  /*
1143  Skip over header (e.g. data:image/gif;base64,).
1144  */
1145  image=NewImageList();
1146  for (p=content; (*p != ',') && (*p != '\0'); p++) ;
1147  if (*p == '\0')
1148  ThrowReaderException(CorruptImageError,"CorruptImage");
1149  blob=Base64Decode(++p,&length);
1150  if (length == 0)
1151  {
1152  blob=(unsigned char *) RelinquishMagickMemory(blob);
1153  ThrowReaderException(CorruptImageError,"CorruptImage");
1154  }
1155  read_info=CloneImageInfo(image_info);
1156  (void) SetImageInfoProgressMonitor(read_info,(MagickProgressMonitor) NULL,
1157  (void *) NULL);
1158  *read_info->filename='\0';
1159  *read_info->magick='\0';
1160  for (p=content; (*p != '/') && (*p != '\0'); p++) ;
1161  if (*p != '\0')
1162  {
1163  char
1164  *q;
1165 
1166  ssize_t
1167  i;
1168 
1169  /*
1170  Extract media type.
1171  */
1172  if (LocaleNCompare(++p,"x-",2) == 0)
1173  p+=(ptrdiff_t) 2;
1174  (void) CopyMagickString(read_info->filename,"data.",MagickPathExtent);
1175  q=read_info->filename+5;
1176  for (i=0; (*p != ';') && (*p != '\0') && (i < (MagickPathExtent-6)); i++)
1177  *q++=(*p++);
1178  *q++='\0';
1179  }
1180  image=BlobToImage(read_info,blob,length,exception);
1181  blob=(unsigned char *) RelinquishMagickMemory(blob);
1182  read_info=DestroyImageInfo(read_info);
1183  return(image);
1184 }
1185 
1186 /*
1187 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1188 % %
1189 % %
1190 % %
1191 % W r i t e I m a g e %
1192 % %
1193 % %
1194 % %
1195 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1196 %
1197 % WriteImage() writes an image or an image sequence to a file or file handle.
1198 % If writing to a file is on disk, the name is defined by the filename member
1199 % of the image structure. WriteImage() returns MagickFalse is there is a
1200 % memory shortage or if the image cannot be written. Check the exception
1201 % member of image to determine the cause for any failure.
1202 %
1203 % The format of the WriteImage method is:
1204 %
1205 % MagickBooleanType WriteImage(const ImageInfo *image_info,Image *image,
1206 % ExceptionInfo *exception)
1207 %
1208 % A description of each parameter follows:
1209 %
1210 % o image_info: the image info.
1211 %
1212 % o image: the image.
1213 %
1214 % o exception: return any errors or warnings in this structure.
1215 %
1216 */
1217 MagickExport MagickBooleanType WriteImage(const ImageInfo *image_info,
1218  Image *image,ExceptionInfo *exception)
1219 {
1220  char
1221  filename[MagickPathExtent];
1222 
1223  const char
1224  *option;
1225 
1226  const DelegateInfo
1227  *delegate_info;
1228 
1229  const MagickInfo
1230  *magick_info;
1231 
1232  EncodeImageHandler
1233  *encoder;
1234 
1236  *sans_exception;
1237 
1238  ImageInfo
1239  *write_info;
1240 
1241  MagickBooleanType
1242  status,
1243  temporary;
1244 
1245  /*
1246  Determine image type from filename prefix or suffix (e.g. image.jpg).
1247  */
1248  assert(image_info != (ImageInfo *) NULL);
1249  assert(image_info->signature == MagickCoreSignature);
1250  assert(image != (Image *) NULL);
1251  if (IsEventLogging() != MagickFalse)
1252  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1253  image_info->filename);
1254  assert(image->signature == MagickCoreSignature);
1255  assert(exception != (ExceptionInfo *) NULL);
1256  sans_exception=AcquireExceptionInfo();
1257  write_info=CloneImageInfo(image_info);
1258  (void) CopyMagickString(write_info->filename,image->filename,
1259  MagickPathExtent);
1260  (void) SetImageInfo(write_info,1,sans_exception);
1261  if (*write_info->magick == '\0')
1262  (void) CopyMagickString(write_info->magick,image->magick,MagickPathExtent);
1263  (void) CopyMagickString(filename,image->filename,MagickPathExtent);
1264  (void) CopyMagickString(image->filename,write_info->filename,
1265  MagickPathExtent);
1266  /*
1267  Call appropriate image writer based on image type.
1268  */
1269  magick_info=GetMagickInfo(write_info->magick,sans_exception);
1270  if (sans_exception->severity == PolicyError)
1271  magick_info=GetMagickInfo(write_info->magick,exception);
1272  sans_exception=DestroyExceptionInfo(sans_exception);
1273  if (magick_info != (const MagickInfo *) NULL)
1274  {
1275  if (GetMagickEndianSupport(magick_info) == MagickFalse)
1276  image->endian=UndefinedEndian;
1277  else
1278  if ((image_info->endian == UndefinedEndian) &&
1279  (GetMagickRawSupport(magick_info) != MagickFalse))
1280  {
1281  unsigned long
1282  lsb_first;
1283 
1284  lsb_first=1;
1285  image->endian=(*(char *) &lsb_first) == 1 ? LSBEndian : MSBEndian;
1286  }
1287  }
1288  SyncImageProfiles(image);
1289  DisassociateImageStream(image);
1290  option=GetImageOption(image_info,"delegate:bimodal");
1291  if ((IsStringTrue(option) != MagickFalse) &&
1292  (write_info->page == (char *) NULL) &&
1293  (GetPreviousImageInList(image) == (Image *) NULL) &&
1294  (GetNextImageInList(image) == (Image *) NULL) &&
1295  (IsTaintImage(image) == MagickFalse) )
1296  {
1297  delegate_info=GetDelegateInfo(image->magick,write_info->magick,exception);
1298  if ((delegate_info != (const DelegateInfo *) NULL) &&
1299  (GetDelegateMode(delegate_info) == 0) &&
1300  (IsPathAccessible(image->magick_filename) != MagickFalse))
1301  {
1302  /*
1303  Process image with bi-modal delegate.
1304  */
1305  (void) CopyMagickString(image->filename,image->magick_filename,
1306  MagickPathExtent);
1307  status=InvokeDelegate(write_info,image,image->magick,
1308  write_info->magick,exception);
1309  write_info=DestroyImageInfo(write_info);
1310  (void) CopyMagickString(image->filename,filename,MagickPathExtent);
1311  return(status);
1312  }
1313  }
1314  status=MagickFalse;
1315  temporary=MagickFalse;
1316  if ((magick_info != (const MagickInfo *) NULL) &&
1317  (GetMagickEncoderSeekableStream(magick_info) != MagickFalse))
1318  {
1319  char
1320  image_filename[MagickPathExtent];
1321 
1322  (void) CopyMagickString(image_filename,image->filename,MagickPathExtent);
1323  status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
1324  (void) CopyMagickString(image->filename, image_filename,MagickPathExtent);
1325  if (status != MagickFalse)
1326  {
1327  if (IsBlobSeekable(image) == MagickFalse)
1328  {
1329  /*
1330  A seekable stream is required by the encoder.
1331  */
1332  write_info->adjoin=MagickTrue;
1333  (void) CopyMagickString(write_info->filename,image->filename,
1334  MagickPathExtent);
1335  (void) AcquireUniqueFilename(image->filename);
1336  temporary=MagickTrue;
1337  }
1338  if (CloseBlob(image) == MagickFalse)
1339  status=MagickFalse;
1340  }
1341  }
1342  encoder=GetImageEncoder(magick_info);
1343  if (encoder != (EncodeImageHandler *) NULL)
1344  {
1345  /*
1346  Call appropriate image writer based on image type.
1347  */
1348  if ((magick_info != (const MagickInfo *) NULL) &&
1349  (GetMagickEncoderThreadSupport(magick_info) == MagickFalse))
1350  LockSemaphoreInfo(magick_info->semaphore);
1351  status=IsCoderAuthorized(write_info->magick,WritePolicyRights,exception);
1352  if (status != MagickFalse)
1353  status=encoder(write_info,image,exception);
1354  if ((magick_info != (const MagickInfo *) NULL) &&
1355  (GetMagickEncoderThreadSupport(magick_info) == MagickFalse))
1356  UnlockSemaphoreInfo(magick_info->semaphore);
1357  }
1358  else
1359  {
1360  delegate_info=GetDelegateInfo((char *) NULL,write_info->magick,exception);
1361  if (delegate_info != (DelegateInfo *) NULL)
1362  {
1363  /*
1364  Process the image with delegate.
1365  */
1366  *write_info->filename='\0';
1367  if (GetDelegateThreadSupport(delegate_info) == MagickFalse)
1368  LockSemaphoreInfo(delegate_info->semaphore);
1369  status=InvokeDelegate(write_info,image,(char *) NULL,
1370  write_info->magick,exception);
1371  if (GetDelegateThreadSupport(delegate_info) == MagickFalse)
1372  UnlockSemaphoreInfo(delegate_info->semaphore);
1373  (void) CopyMagickString(image->filename,filename,MagickPathExtent);
1374  }
1375  else
1376  {
1377  sans_exception=AcquireExceptionInfo();
1378  magick_info=GetMagickInfo(write_info->magick,sans_exception);
1379  if (sans_exception->severity == PolicyError)
1380  magick_info=GetMagickInfo(write_info->magick,exception);
1381  sans_exception=DestroyExceptionInfo(sans_exception);
1382  if ((write_info->affirm == MagickFalse) &&
1383  (magick_info == (const MagickInfo *) NULL))
1384  {
1385  (void) CopyMagickString(write_info->magick,image->magick,
1386  MagickPathExtent);
1387  magick_info=GetMagickInfo(write_info->magick,exception);
1388  }
1389  encoder=GetImageEncoder(magick_info);
1390  if (encoder == (EncodeImageHandler *) NULL)
1391  {
1392  char
1393  extension[MagickPathExtent];
1394 
1395  GetPathComponent(image->filename,ExtensionPath,extension);
1396  if (*extension != '\0')
1397  magick_info=GetMagickInfo(extension,exception);
1398  else
1399  magick_info=GetMagickInfo(image->magick,exception);
1400  (void) CopyMagickString(image->filename,filename,
1401  MagickPathExtent);
1402  encoder=GetImageEncoder(magick_info);
1403  (void) ThrowMagickException(exception,GetMagickModule(),
1404  MissingDelegateWarning,"NoEncodeDelegateForThisImageFormat",
1405  "`%s'",write_info->magick);
1406  }
1407  if (encoder == (EncodeImageHandler *) NULL)
1408  {
1409  magick_info=GetMagickInfo(image->magick,exception);
1410  encoder=GetImageEncoder(magick_info);
1411  if (encoder == (EncodeImageHandler *) NULL)
1412  (void) ThrowMagickException(exception,GetMagickModule(),
1413  MissingDelegateError,"NoEncodeDelegateForThisImageFormat",
1414  "`%s'",write_info->magick);
1415  }
1416  if (encoder != (EncodeImageHandler *) NULL)
1417  {
1418  /*
1419  Call appropriate image writer based on image type.
1420  */
1421  if (GetMagickEncoderThreadSupport(magick_info) == MagickFalse)
1422  LockSemaphoreInfo(magick_info->semaphore);
1423  status=IsCoderAuthorized(write_info->magick,WritePolicyRights,
1424  exception);
1425  if (status != MagickFalse)
1426  status=encoder(write_info,image,exception);
1427  if (GetMagickEncoderThreadSupport(magick_info) == MagickFalse)
1428  UnlockSemaphoreInfo(magick_info->semaphore);
1429  }
1430  }
1431  }
1432  if (temporary != MagickFalse)
1433  {
1434  /*
1435  Copy temporary image file to permanent.
1436  */
1437  status=OpenBlob(write_info,image,ReadBinaryBlobMode,exception);
1438  if (status != MagickFalse)
1439  {
1440  (void) RelinquishUniqueFileResource(write_info->filename);
1441  status=ImageToFile(image,write_info->filename,exception);
1442  }
1443  if (CloseBlob(image) == MagickFalse)
1444  status=MagickFalse;
1445  (void) RelinquishUniqueFileResource(image->filename);
1446  (void) CopyMagickString(image->filename,write_info->filename,
1447  MagickPathExtent);
1448  }
1449  if ((LocaleCompare(write_info->magick,"info") != 0) &&
1450  (write_info->verbose != MagickFalse))
1451  (void) IdentifyImage(image,stdout,MagickFalse,exception);
1452  write_info=DestroyImageInfo(write_info);
1453  if (GetBlobError(image) != MagickFalse)
1454  ThrowWriterException(FileOpenError,"UnableToWriteFile");
1455  return(status);
1456 }
1457 
1458 /*
1459 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1460 % %
1461 % %
1462 % %
1463 % W r i t e I m a g e s %
1464 % %
1465 % %
1466 % %
1467 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1468 %
1469 % WriteImages() writes an image sequence into one or more files. While
1470 % WriteImage() can write an image sequence, it is limited to writing
1471 % the sequence into a single file using a format which supports multiple
1472 % frames. WriteImages(), however, does not have this limitation, instead it
1473 % generates multiple output files if necessary (or when requested). When
1474 % ImageInfo's adjoin flag is set to MagickFalse, the file name is expected
1475 % to include a printf-style formatting string for the frame number (e.g.
1476 % "image%02d.png").
1477 %
1478 % The format of the WriteImages method is:
1479 %
1480 % MagickBooleanType WriteImages(const ImageInfo *image_info,Image *images,
1481 % const char *filename,ExceptionInfo *exception)
1482 %
1483 % A description of each parameter follows:
1484 %
1485 % o image_info: the image info.
1486 %
1487 % o images: the image list.
1488 %
1489 % o filename: the image filename.
1490 %
1491 % o exception: return any errors or warnings in this structure.
1492 %
1493 */
1494 MagickExport MagickBooleanType WriteImages(const ImageInfo *image_info,
1495  Image *images,const char *filename,ExceptionInfo *exception)
1496 {
1497 #define WriteImageTag "Write/Image"
1498 
1500  *sans_exception;
1501 
1502  ImageInfo
1503  *write_info;
1504 
1505  MagickBooleanType
1506  proceed;
1507 
1508  MagickOffsetType
1509  progress;
1510 
1511  MagickProgressMonitor
1512  progress_monitor;
1513 
1514  MagickSizeType
1515  number_images;
1516 
1517  MagickStatusType
1518  status;
1519 
1520  Image
1521  *p;
1522 
1523  assert(image_info != (const ImageInfo *) NULL);
1524  assert(image_info->signature == MagickCoreSignature);
1525  assert(images != (Image *) NULL);
1526  assert(images->signature == MagickCoreSignature);
1527  if (IsEventLogging() != MagickFalse)
1528  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
1529  assert(exception != (ExceptionInfo *) NULL);
1530  write_info=CloneImageInfo(image_info);
1531  *write_info->magick='\0';
1532  images=GetFirstImageInList(images);
1533  if (images == (Image *) NULL)
1534  return(MagickFalse);
1535  if (filename != (const char *) NULL)
1536  for (p=images; p != (Image *) NULL; p=GetNextImageInList(p))
1537  (void) CopyMagickString(p->filename,filename,MagickPathExtent);
1538  (void) CopyMagickString(write_info->filename,images->filename,
1539  MagickPathExtent);
1540  sans_exception=AcquireExceptionInfo();
1541  (void) SetImageInfo(write_info,(unsigned int) GetImageListLength(images),
1542  sans_exception);
1543  sans_exception=DestroyExceptionInfo(sans_exception);
1544  if (*write_info->magick == '\0')
1545  (void) CopyMagickString(write_info->magick,images->magick,MagickPathExtent);
1546  p=images;
1547  for ( ; GetNextImageInList(p) != (Image *) NULL; p=GetNextImageInList(p))
1548  {
1549  if (p->scene >= GetNextImageInList(p)->scene)
1550  {
1551  ssize_t
1552  i;
1553 
1554  /*
1555  Generate consistent scene numbers.
1556  */
1557  i=(ssize_t) images->scene;
1558  for (p=images; p != (Image *) NULL; p=GetNextImageInList(p))
1559  p->scene=(size_t) i++;
1560  break;
1561  }
1562  }
1563  /*
1564  Write images.
1565  */
1566  status=MagickTrue;
1567  progress_monitor=(MagickProgressMonitor) NULL;
1568  progress=0;
1569  number_images=GetImageListLength(images);
1570  for (p=images; p != (Image *) NULL; p=GetNextImageInList(p))
1571  {
1572  if (number_images != 1)
1573  progress_monitor=SetImageProgressMonitor(p,(MagickProgressMonitor) NULL,
1574  p->client_data);
1575  status&=(MagickStatusType) WriteImage(write_info,p,exception);
1576  if (number_images != 1)
1577  (void) SetImageProgressMonitor(p,progress_monitor,p->client_data);
1578  if (write_info->adjoin != MagickFalse)
1579  break;
1580  if (number_images != 1)
1581  {
1582 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1583  #pragma omp atomic
1584 #endif
1585  progress++;
1586  proceed=SetImageProgress(p,WriteImageTag,progress,number_images);
1587  if (proceed == MagickFalse)
1588  break;
1589  }
1590  }
1591  write_info=DestroyImageInfo(write_info);
1592  return(status != 0 ? MagickTrue : MagickFalse);
1593 }
_RectangleInfo
Definition: geometry.h:129
_ConstituteInfo
Definition: constitute.c:93
_MagickInfo
Definition: magick.h:66
_GeometryInfo
Definition: geometry.h:105
_Image
Definition: image.h:131
_ImageInfo
Definition: image.h:358
_ExceptionInfo
Definition: exception.h:101
_DelegateInfo
Definition: delegate.h:28
_StringInfo
Definition: string_.h:27