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