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