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