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