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