Coverage Report

Created: 2026-11-12 07:35

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/imagemagick/MagickCore/constitute.c
Line
Count
Source
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;
115
} ConstituteInfo;
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
111
{
170
111
  Image
171
111
    *image;
172
173
111
  MagickBooleanType
174
111
    status;
175
176
111
  ssize_t
177
111
    i;
178
179
111
  size_t
180
111
    length;
181
182
  /*
183
    Allocate image structure.
184
  */
185
111
  assert(map != (const char *) NULL);
186
111
  assert(pixels != (void *) NULL);
187
111
  assert(exception != (ExceptionInfo *) NULL);
188
111
  assert(exception->signature == MagickCoreSignature);
189
111
  if (IsEventLogging() != MagickFalse)
190
0
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",map);
191
111
  image=AcquireImage((ImageInfo *) NULL,exception);
192
111
  if (image == (Image *) NULL)
193
0
    return((Image *) NULL);
194
111
  switch (storage)
195
111
  {
196
111
    case CharPixel: image->depth=8*sizeof(unsigned char); break;
197
0
    case DoublePixel: image->depth=8*sizeof(double); break;
198
0
    case FloatPixel: image->depth=8*sizeof(float); break;
199
0
    case LongPixel: image->depth=8*sizeof(unsigned long); break;
200
0
    case LongLongPixel: image->depth=8*sizeof(MagickSizeType); break;
201
0
    case ShortPixel: image->depth=8*sizeof(unsigned short); break;
202
0
    default: break;
203
111
  }
204
111
  length=strlen(map);
205
444
  for (i=0; i < (ssize_t) length; i++)
206
333
  {
207
333
    switch (map[i])
208
333
    {
209
0
      case 'a':
210
0
      case 'A':
211
0
      case 'O':
212
0
      case 'o':
213
0
      {
214
0
        image->alpha_trait=BlendPixelTrait;
215
0
        break;
216
0
      }
217
0
      case 'C':
218
0
      case 'c':
219
0
      case 'm':
220
0
      case 'M':
221
0
      case 'Y':
222
0
      case 'y':
223
0
      case 'K':
224
0
      case 'k':
225
0
      {
226
0
        image->colorspace=CMYKColorspace;
227
0
        break;
228
0
      }
229
0
      case 'I':
230
0
      case 'i':
231
0
      {
232
0
        image->colorspace=GRAYColorspace;
233
0
        break;
234
0
      }
235
333
      default:
236
333
      {
237
333
        if (length == 1)
238
0
          image->colorspace=GRAYColorspace;
239
333
        break;
240
0
      }
241
333
    }
242
333
  }
243
111
  status=SetImageExtent(image,columns,rows,exception);
244
111
  if (status == MagickFalse)
245
0
    return(DestroyImageList(image));
246
111
  status=ResetImagePixels(image,exception);
247
111
  if (status == MagickFalse)
248
0
    return(DestroyImageList(image));
249
111
  status=ImportImagePixels(image,0,0,columns,rows,map,storage,pixels,exception);
250
111
  if (status == MagickFalse)
251
0
    image=DestroyImage(image);
252
111
  return(image);
253
111
}
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
0
{
291
0
  magick_unreferenced(image);
292
0
  magick_unreferenced(pixels);
293
0
  return(columns);
294
0
}
295
296
#if defined(__cplusplus) || defined(c_plusplus)
297
}
298
#endif
299
300
MagickExport Image *PingImage(const ImageInfo *image_info,
301
  ExceptionInfo *exception)
302
0
{
303
0
  Image
304
0
    *image;
305
306
0
  ImageInfo
307
0
    *ping_info;
308
309
0
  assert(image_info != (ImageInfo *) NULL);
310
0
  assert(image_info->signature == MagickCoreSignature);
311
0
  assert(exception != (ExceptionInfo *) NULL);
312
0
  if (IsEventLogging() != MagickFalse)
313
0
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
314
0
      image_info->filename);
315
0
  ping_info=CloneImageInfo(image_info);
316
0
  ping_info->ping=MagickTrue;
317
0
  image=ReadStream(ping_info,&PingStream,exception);
318
0
  if (image != (Image *) NULL)
319
0
    {
320
0
      if ((image->columns == 0) || (image->rows == 0))
321
0
        ThrowReaderException(CorruptImageError,"ImproperImageHeader");
322
0
      ResetTimer(&image->timer);
323
0
      if (ping_info->verbose != MagickFalse)
324
0
        (void) IdentifyImage(image,stdout,MagickFalse,exception);
325
0
    }
326
0
  ping_info=DestroyImageInfo(ping_info);
327
0
  return(image);
328
0
}
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
0
{
360
0
  char
361
0
    ping_filename[MagickPathExtent];
362
363
0
  Image
364
0
    *image,
365
0
    *images;
366
367
0
  ImageInfo
368
0
    *read_info;
369
370
  /*
371
    Ping image list from a file.
372
  */
373
0
  assert(image_info != (ImageInfo *) NULL);
374
0
  assert(image_info->signature == MagickCoreSignature);
375
0
  assert(exception != (ExceptionInfo *) NULL);
376
0
  if (IsEventLogging() != MagickFalse)
377
0
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
378
0
      image_info->filename);
379
0
  (void) SetImageOption(image_info,"filename",filename);
380
0
  (void) CopyMagickString(image_info->filename,filename,MagickPathExtent);
381
0
  (void) InterpretImageFilename(image_info,(Image *) NULL,image_info->filename,
382
0
    (int) image_info->scene,ping_filename,exception);
383
0
  if (LocaleCompare(ping_filename,image_info->filename) != 0)
384
0
    {
385
0
      ExceptionInfo
386
0
        *sans;
387
388
0
      ssize_t
389
0
        extent,
390
0
        scene;
391
392
      /*
393
        Images of the form image-%d.png[1-5].
394
      */
395
0
      read_info=CloneImageInfo(image_info);
396
0
      sans=AcquireExceptionInfo();
397
0
      (void) SetImageInfo(read_info,0,sans);
398
0
      sans=DestroyExceptionInfo(sans);
399
0
      if (read_info->number_scenes == 0)
400
0
        {
401
0
          read_info=DestroyImageInfo(read_info);
402
0
          return(PingImage(image_info,exception));
403
0
        }
404
0
      (void) CopyMagickString(ping_filename,read_info->filename,
405
0
        MagickPathExtent);
406
0
      images=NewImageList();
407
0
      extent=(ssize_t) (read_info->scene+read_info->number_scenes);
408
0
      for (scene=(ssize_t) read_info->scene; scene < (ssize_t) extent; scene++)
409
0
      {
410
0
        (void) InterpretImageFilename(image_info,(Image *) NULL,ping_filename,
411
0
          (int) scene,read_info->filename,exception);
412
0
        image=PingImage(read_info,exception);
413
0
        if (image == (Image *) NULL)
414
0
          continue;
415
0
        AppendImageToList(&images,image);
416
0
      }
417
0
      read_info=DestroyImageInfo(read_info);
418
0
      return(images);
419
0
    }
420
0
  return(PingImage(image_info,exception));
421
0
}
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
941k
{
455
941k
  if (IsRightsAuthorized(CoderPolicyDomain,rights,coder) == MagickFalse)
456
941k
    ThrowPolicyException(coder,MagickFalse);
457
941k
  if (IsRightsAuthorized(ModulePolicyDomain,rights,module) == MagickFalse)
458
941k
    ThrowPolicyException(module,MagickFalse);
459
941k
  return(MagickTrue);
460
941k
}
461
462
static void InitializeConstituteInfo(const ImageInfo *image_info,
463
  ConstituteInfo *constitute_info)
464
195k
{
465
195k
  const char
466
195k
    *option;
467
468
195k
  memset(constitute_info,0,sizeof(*constitute_info));
469
195k
  constitute_info->sync_from_exif=MagickTrue;
470
195k
  constitute_info->sync_from_tiff=MagickTrue;
471
195k
  option=GetImageOption(image_info,"exif:sync-image");
472
195k
  if (IsStringFalse(option) != MagickFalse)
473
0
    constitute_info->sync_from_exif=MagickFalse;
474
195k
  option=GetImageOption(image_info,"tiff:sync-image");
475
195k
  if (IsStringFalse(option) != MagickFalse)
476
0
    constitute_info->sync_from_tiff=MagickFalse;
477
195k
  constitute_info->caption=GetImageOption(image_info,"caption");
478
195k
  constitute_info->comment=GetImageOption(image_info,"comment");
479
195k
  constitute_info->label=GetImageOption(image_info,"label");
480
195k
  option=GetImageOption(image_info,"delay");
481
195k
  if (option != (const char *) NULL)
482
0
    {
483
0
      GeometryInfo
484
0
        geometry_info;
485
486
0
      constitute_info->delay_flags=ParseGeometry(option,&geometry_info);
487
0
      if (constitute_info->delay_flags != NoValue)
488
0
        {
489
0
          constitute_info->delay=(size_t) floor(geometry_info.rho+0.5);
490
0
          if ((constitute_info->delay_flags & SigmaValue) != 0)
491
0
            constitute_info->ticks_per_second=CastDoubleToSsizeT(floor(
492
0
              geometry_info.sigma+0.5));
493
0
        }
494
0
    }
495
195k
}
496
497
static void SyncOrientationFromProperties(Image *image,
498
  ConstituteInfo *constitute_info,ExceptionInfo *exception)
499
221k
{
500
221k
  const char
501
221k
    *orientation;
502
503
221k
  orientation=(const char *) NULL;
504
221k
  if (constitute_info->sync_from_exif != MagickFalse)
505
221k
    {
506
221k
      orientation=GetImageProperty(image,"exif:Orientation",exception);
507
221k
      if (orientation != (const char *) NULL)
508
2.57k
        {
509
2.57k
          image->orientation=(OrientationType) StringToLong(orientation);
510
2.57k
          (void) DeleteImageProperty(image,"exif:Orientation");
511
2.57k
        }
512
221k
    }
513
221k
  if ((orientation == (const char *) NULL) &&
514
219k
      (constitute_info->sync_from_tiff != MagickFalse))
515
219k
    {
516
219k
      orientation=GetImageProperty(image,"tiff:Orientation",exception);
517
219k
      if (orientation != (const char *) NULL)
518
0
        {
519
0
          image->orientation=(OrientationType) StringToLong(orientation);
520
0
          (void) DeleteImageProperty(image,"tiff:Orientation");
521
0
        }
522
219k
    }
523
221k
}
524
525
static void SyncResolutionFromProperties(Image *image,
526
  ConstituteInfo *constitute_info, ExceptionInfo *exception)
527
221k
{
528
221k
  const char
529
221k
    *resolution_x,
530
221k
    *resolution_y,
531
221k
    *resolution_units;
532
533
221k
  MagickBooleanType
534
221k
    used_tiff;
535
536
221k
  resolution_x=(const char *) NULL;
537
221k
  resolution_y=(const char *) NULL;
538
221k
  resolution_units=(const char *) NULL;
539
221k
  used_tiff=MagickFalse;
540
221k
  if (constitute_info->sync_from_exif != MagickFalse)
541
221k
    {
542
221k
      resolution_x=GetImageProperty(image,"exif:XResolution",exception);
543
221k
      resolution_y=GetImageProperty(image,"exif:YResolution",exception);
544
221k
      if ((resolution_x != (const char *) NULL) &&
545
8.83k
          (resolution_y != (const char *) NULL))
546
7.65k
        resolution_units=GetImageProperty(image,"exif:ResolutionUnit",
547
7.65k
          exception);
548
221k
    }
549
221k
  if ((resolution_x == (const char *) NULL) &&
550
213k
      (resolution_y == (const char *) NULL) &&
551
212k
      (constitute_info->sync_from_tiff != MagickFalse))
552
212k
    {
553
212k
      resolution_x=GetImageProperty(image,"tiff:XResolution",exception);
554
212k
      resolution_y=GetImageProperty(image,"tiff:YResolution",exception);
555
212k
      if ((resolution_x != (const char *) NULL) &&
556
103
          (resolution_y != (const char *) NULL))
557
103
        {
558
103
          used_tiff=MagickTrue;
559
103
          resolution_units=GetImageProperty(image,"tiff:ResolutionUnit",
560
103
            exception);
561
103
        }
562
212k
    }
563
221k
  if ((resolution_x != (const char *) NULL) &&
564
8.94k
      (resolution_y != (const char *) NULL))
565
7.75k
    {
566
7.75k
      GeometryInfo
567
7.75k
        geometry_info;
568
569
7.75k
      ssize_t
570
7.75k
        option_type;
571
572
7.75k
      geometry_info.rho=image->resolution.x;
573
7.75k
      geometry_info.sigma=1.0;
574
7.75k
      (void) ParseGeometry(resolution_x,&geometry_info);
575
7.75k
      if (geometry_info.sigma != 0)
576
2.73k
        image->resolution.x=geometry_info.rho/geometry_info.sigma;
577
7.75k
      if (strchr(resolution_x,',') != (char *) NULL)
578
2.06k
        image->resolution.x=geometry_info.rho+geometry_info.sigma/1000.0;
579
7.75k
      geometry_info.rho=image->resolution.y;
580
7.75k
      geometry_info.sigma=1.0;
581
7.75k
      (void) ParseGeometry(resolution_y,&geometry_info);
582
7.75k
      if (geometry_info.sigma != 0)
583
3.08k
        image->resolution.y=geometry_info.rho/geometry_info.sigma;
584
7.75k
      if (strchr(resolution_y,',') != (char *) NULL)
585
2.59k
        image->resolution.y=geometry_info.rho+geometry_info.sigma/1000.0;
586
7.75k
      if (resolution_units != (char *) NULL)
587
1.77k
        {
588
1.77k
          option_type=ParseCommandOption(MagickResolutionOptions,MagickFalse,
589
1.77k
            resolution_units);
590
1.77k
          if (option_type >= 0)
591
280
            image->units=(ResolutionType) option_type;
592
1.77k
        }
593
7.75k
      if (used_tiff == MagickFalse)
594
7.65k
        {
595
7.65k
          (void) DeleteImageProperty(image,"exif:XResolution");
596
7.65k
          (void) DeleteImageProperty(image,"exif:YResolution");
597
7.65k
          (void) DeleteImageProperty(image,"exif:ResolutionUnit");
598
7.65k
        }
599
103
      else
600
103
        {
601
103
          (void) DeleteImageProperty(image,"tiff:XResolution");
602
103
          (void) DeleteImageProperty(image,"tiff:YResolution");
603
103
          (void) DeleteImageProperty(image,"tiff:ResolutionUnit");
604
103
        }
605
7.75k
    }
606
221k
}
607
608
static Image *ReadImageInternal(const ImageInfo *image_info,
609
  const MagickBooleanType postprocess,ExceptionInfo *exception)
610
878k
{
611
878k
  char
612
878k
    filename[MagickPathExtent],
613
878k
    magick[MagickPathExtent],
614
878k
    magick_filename[MagickPathExtent];
615
616
878k
  ConstituteInfo
617
878k
    constitute_info;
618
619
878k
  const DelegateInfo
620
878k
    *delegate_info;
621
622
878k
  const MagickInfo
623
878k
    *magick_info;
624
625
878k
  DecodeImageHandler
626
878k
    *decoder;
627
628
878k
  ExceptionInfo
629
878k
    *sans_exception;
630
631
878k
  Image
632
878k
    *image,
633
878k
    *next;
634
635
878k
  ImageInfo
636
878k
    *read_info;
637
638
878k
  MagickBooleanType
639
878k
    status;
640
641
  /*
642
    Determine image type from filename prefix or suffix (e.g. image.jpg).
643
  */
644
878k
  assert(image_info != (ImageInfo *) NULL);
645
878k
  assert(image_info->signature == MagickCoreSignature);
646
878k
  assert(image_info->filename != (char *) NULL);
647
878k
  if (IsEventLogging() != MagickFalse)
648
0
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
649
0
      image_info->filename);
650
878k
  assert(exception != (ExceptionInfo *) NULL);
651
878k
  read_info=CloneImageInfo(image_info);
652
878k
  (void) CopyMagickString(magick_filename,read_info->filename,MagickPathExtent);
653
878k
  (void) SetImageInfo(read_info,0,exception);
654
878k
  (void) CopyMagickString(filename,read_info->filename,MagickPathExtent);
655
878k
  (void) CopyMagickString(magick,read_info->magick,MagickPathExtent);
656
  /*
657
    Call appropriate image reader based on image type.
658
  */
659
878k
  sans_exception=AcquireExceptionInfo();
660
878k
  magick_info=GetMagickInfo(read_info->magick,sans_exception);
661
878k
  if (sans_exception->severity == PolicyError)
662
0
    InheritException(exception,sans_exception);
663
878k
  sans_exception=DestroyExceptionInfo(sans_exception);
664
878k
  if (magick_info != (const MagickInfo *) NULL)
665
878k
    {
666
878k
      if (GetMagickEndianSupport(magick_info) == MagickFalse)
667
737k
        read_info->endian=UndefinedEndian;
668
140k
      else
669
140k
        if ((image_info->endian == UndefinedEndian) &&
670
140k
            (GetMagickRawSupport(magick_info) != MagickFalse))
671
8.84k
          read_info->endian=GetHostEndian();
672
878k
    }
673
878k
  if ((magick_info != (const MagickInfo *) NULL) &&
674
878k
      (GetMagickDecoderSeekableStream(magick_info) != MagickFalse))
675
698k
    {
676
698k
      image=AcquireImage(read_info,exception);
677
698k
      (void) CopyMagickString(image->filename,read_info->filename,
678
698k
        MagickPathExtent);
679
698k
      status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
680
698k
      if (status == MagickFalse)
681
0
        {
682
0
          read_info=DestroyImageInfo(read_info);
683
0
          image=DestroyImage(image);
684
0
          return((Image *) NULL);
685
0
        }
686
698k
      if (IsBlobSeekable(image) == MagickFalse)
687
0
        {
688
          /*
689
            Coder requires a seekable stream.
690
          */
691
0
          *read_info->filename='\0';
692
0
          status=ImageToFile(image,read_info->filename,exception);
693
0
          if (status == MagickFalse)
694
0
            {
695
0
              (void) CloseBlob(image);
696
0
              read_info=DestroyImageInfo(read_info);
697
0
              image=DestroyImage(image);
698
0
              return((Image *) NULL);
699
0
            }
700
0
          read_info->temporary=MagickTrue;
701
0
        }
702
698k
      (void) CloseBlob(image);
703
698k
      image=DestroyImage(image);
704
698k
    }
705
878k
  image=NewImageList();
706
878k
  decoder=GetImageDecoder(magick_info);
707
878k
  if (decoder == (DecodeImageHandler *) NULL)
708
1.10k
    {
709
1.10k
      delegate_info=GetDelegateInfo(read_info->magick,(char *) NULL,exception);
710
1.10k
      if (delegate_info == (const DelegateInfo *) NULL)
711
1.08k
        {
712
1.08k
          (void) SetImageInfo(read_info,0,exception);
713
1.08k
          (void) CopyMagickString(read_info->filename,filename,
714
1.08k
            MagickPathExtent);
715
1.08k
          magick_info=GetMagickInfo(read_info->magick,exception);
716
1.08k
          decoder=GetImageDecoder(magick_info);
717
1.08k
        }
718
1.10k
    }
719
878k
  if (decoder != (DecodeImageHandler *) NULL)
720
878k
    {
721
      /*
722
        Call appropriate image reader based on image type.
723
      */
724
878k
      if (GetMagickDecoderThreadSupport(magick_info) == MagickFalse)
725
2.28k
        LockSemaphoreInfo(magick_info->semaphore);
726
878k
      status=IsCoderAuthorized(magick_info->magick_module,magick_info->name,
727
878k
        ReadPolicyRights,exception);
728
878k
      image=(Image *) NULL;
729
878k
      if (status != MagickFalse)
730
878k
        image=decoder(read_info,exception);
731
878k
      if (GetMagickDecoderThreadSupport(magick_info) == MagickFalse)
732
2.28k
        UnlockSemaphoreInfo(magick_info->semaphore);
733
878k
    }
734
311
  else
735
311
    {
736
311
      delegate_info=GetDelegateInfo(read_info->magick,(char *) NULL,exception);
737
311
      if (delegate_info == (const DelegateInfo *) NULL)
738
291
        {
739
291
          (void) ThrowMagickException(exception,GetMagickModule(),
740
291
            MissingDelegateError,"NoDecodeDelegateForThisImageFormat","`%s'",
741
291
            read_info->filename);
742
291
          if (read_info->temporary != MagickFalse)
743
0
            (void) RelinquishUniqueFileResource(read_info->filename);
744
291
          read_info=DestroyImageInfo(read_info);
745
291
          return((Image *) NULL);
746
291
        }
747
      /*
748
        Let our decoding delegate process the image.
749
      */
750
20
      image=AcquireImage(read_info,exception);
751
20
      if (image == (Image *) NULL)
752
0
        {
753
0
          read_info=DestroyImageInfo(read_info);
754
0
          return((Image *) NULL);
755
0
        }
756
20
      (void) CopyMagickString(image->filename,read_info->filename,
757
20
        MagickPathExtent);
758
20
      *read_info->filename='\0';
759
20
      if (GetDelegateThreadSupport(delegate_info) == MagickFalse)
760
0
        LockSemaphoreInfo(delegate_info->semaphore);
761
20
      status=InvokeDelegate(read_info,image,read_info->magick,(char *) NULL,
762
20
        exception);
763
20
      if (GetDelegateThreadSupport(delegate_info) == MagickFalse)
764
0
        UnlockSemaphoreInfo(delegate_info->semaphore);
765
20
      image=DestroyImageList(image);
766
20
      read_info->temporary=MagickTrue;
767
20
      (void) DeleteImageOption(read_info,"filename:literal");
768
20
      if (status != MagickFalse)
769
0
        (void) SetImageInfo(read_info,0,exception);
770
20
      magick_info=GetMagickInfo(read_info->magick,exception);
771
20
      decoder=GetImageDecoder(magick_info);
772
20
      if (decoder == (DecodeImageHandler *) NULL)
773
20
        {
774
20
          if (IsPathAccessible(read_info->filename) != MagickFalse)
775
20
            (void) ThrowMagickException(exception,GetMagickModule(),
776
20
              MissingDelegateError,"NoDecodeDelegateForThisImageFormat","`%s'",
777
20
              read_info->magick);
778
0
          else
779
0
            ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
780
20
              read_info->filename);
781
20
          read_info=DestroyImageInfo(read_info);
782
20
          return((Image *) NULL);
783
20
        }
784
      /*
785
        Call appropriate image reader based on image type.
786
      */
787
0
      if (GetMagickDecoderThreadSupport(magick_info) == MagickFalse)
788
0
        LockSemaphoreInfo(magick_info->semaphore);
789
0
      status=IsCoderAuthorized(magick_info->magick_module,magick_info->name,
790
0
        ReadPolicyRights,exception);
791
0
      image=(Image *) NULL;
792
0
      if (status != MagickFalse)
793
0
        image=(decoder)(read_info,exception);
794
0
      if (GetMagickDecoderThreadSupport(magick_info) == MagickFalse)
795
0
        UnlockSemaphoreInfo(magick_info->semaphore);
796
0
    }
797
878k
  if (read_info->temporary != MagickFalse)
798
0
    {
799
0
      (void) RelinquishUniqueFileResource(read_info->filename);
800
0
      read_info->temporary=MagickFalse;
801
0
      if (image != (Image *) NULL)
802
0
        (void) CopyMagickString(image->filename,filename,MagickPathExtent);
803
0
    }
804
878k
  if (image == (Image *) NULL)
805
587k
    {
806
587k
      read_info=DestroyImageInfo(read_info);
807
587k
      return(image);
808
587k
    }
809
290k
  if (IsBlobTemporary(image) != MagickFalse)
810
0
    (void) RelinquishUniqueFileResource(read_info->filename);
811
290k
  if (exception->severity >= ErrorException)
812
94.9k
    {
813
94.9k
      (void) LogMagickEvent(ExceptionEvent,GetMagickModule(),
814
94.9k
        "Coder (%s) generated an image despite an error (%d), "
815
94.9k
        "notify the developers",image->magick,exception->severity);
816
94.9k
      return(DestroyImageList(image));
817
94.9k
    }
818
195k
  if (read_info->ping != MagickFalse)
819
3.61k
    {
820
7.84k
      for (next=image; next != (Image *) NULL; next=GetNextImageInList(next))
821
4.23k
      {
822
4.23k
        if ((image->columns == 0) || (image->rows == 0))
823
8
          {
824
8
            read_info=DestroyImageInfo(read_info);
825
8
            ThrowReaderException(ImageError,"NegativeOrZeroImageSize");
826
0
          }
827
4.23k
      }
828
3.61k
    }
829
195k
  if ((postprocess != MagickFalse) &&
830
195k
      (IsSceneGeometry(read_info->scenes,MagickFalse) != MagickFalse) &&
831
1.94k
      (GetImageListLength(image) != 1))
832
0
    {
833
0
      Image
834
0
        *clones;
835
836
0
      clones=CloneImages(image,read_info->scenes,exception);
837
0
      image=DestroyImageList(image);
838
0
      if (clones != (Image *) NULL)
839
0
        image=GetFirstImageInList(clones);
840
0
      if (image == (Image *) NULL)
841
0
        {
842
0
          read_info=DestroyImageInfo(read_info);
843
0
          return(image);
844
0
        }
845
0
    }
846
195k
  InitializeConstituteInfo(read_info,&constitute_info);
847
417k
  for (next=image; next != (Image *) NULL; next=GetNextImageInList(next))
848
222k
  {
849
222k
    char
850
222k
      magick_path[MagickPathExtent],
851
222k
      *property;
852
853
222k
    const StringInfo
854
222k
      *profile;
855
856
222k
    next->taint=MagickFalse;
857
222k
    GetPathComponent(magick_filename,MagickPath,magick_path);
858
222k
    if ((*magick_path == '\0') && (*next->magick == '\0'))
859
0
      (void) CopyMagickString(next->magick,magick,MagickPathExtent);
860
222k
    (void) CopyMagickString(next->magick_filename,magick_filename,
861
222k
      MagickPathExtent);
862
222k
    if (IsBlobTemporary(image) != MagickFalse)
863
0
      (void) CopyMagickString(next->filename,filename,MagickPathExtent);
864
222k
    if (next->magick_columns == 0)
865
204k
      next->magick_columns=next->columns;
866
222k
    if (next->magick_rows == 0)
867
204k
      next->magick_rows=next->rows;
868
222k
    if (postprocess == MagickFalse)
869
80
      {
870
80
        image=next;
871
80
        continue;
872
80
      }
873
221k
    (void) GetImageProperty(next,"exif:*",exception);
874
221k
    (void) GetImageProperty(next,"icc:*",exception);
875
221k
    (void) GetImageProperty(next,"iptc:*",exception);
876
221k
    (void) GetImageProperty(next,"xmp:*",exception);
877
221k
    SyncOrientationFromProperties(next,&constitute_info,exception);
878
221k
    SyncResolutionFromProperties(next,&constitute_info,exception);
879
221k
    if (next->page.width == 0)
880
188k
      next->page.width=next->columns;
881
221k
    if (next->page.height == 0)
882
188k
      next->page.height=next->rows;
883
221k
    if (constitute_info.caption != (const char *) NULL)
884
0
      {
885
0
        property=InterpretImageProperties(read_info,next,
886
0
          constitute_info.caption,exception);
887
0
        (void) SetImageProperty(next,"caption",property,exception);
888
0
        property=DestroyString(property);
889
0
      }
890
221k
    if (constitute_info.comment != (const char *) NULL)
891
0
      {
892
0
        property=InterpretImageProperties(read_info,next,
893
0
          constitute_info.comment,exception);
894
0
        (void) SetImageProperty(next,"comment",property,exception);
895
0
        property=DestroyString(property);
896
0
      }
897
221k
    if (constitute_info.label != (const char *) NULL)
898
0
      {
899
0
        property=InterpretImageProperties(read_info,next,
900
0
          constitute_info.label,exception);
901
0
        (void) SetImageProperty(next,"label",property,exception);
902
0
        property=DestroyString(property);
903
0
      }
904
221k
    if (LocaleCompare(next->magick,"TEXT") == 0)
905
0
      (void) ParseAbsoluteGeometry("0x0+0+0",&next->page);
906
221k
    if ((read_info->extract != (char *) NULL) &&
907
12.8k
        (read_info->stream == (StreamHandler) NULL))
908
12.8k
      {
909
12.8k
        RectangleInfo
910
12.8k
          geometry;
911
912
12.8k
        MagickStatusType
913
12.8k
          flags;
914
915
12.8k
        SetGeometry(next,&geometry);
916
12.8k
        flags=ParseAbsoluteGeometry(read_info->extract,&geometry);
917
12.8k
        if ((next->columns != geometry.width) ||
918
2.84k
            (next->rows != geometry.height))
919
11.0k
          {
920
11.0k
            if (((flags & XValue) != 0) || ((flags & YValue) != 0))
921
2.88k
              {
922
2.88k
                Image *crop_image = CropImage(next,&geometry,exception);
923
2.88k
                if (crop_image != (Image *) NULL)
924
1.92k
                  ReplaceImageInList(&next,crop_image);
925
2.88k
              }
926
8.19k
            else
927
8.19k
              if (((flags & WidthValue) != 0) || ((flags & HeightValue) != 0))
928
7.81k
                {
929
7.81k
                  flags=ParseRegionGeometry(next,read_info->extract,&geometry,
930
7.81k
                    exception);
931
7.81k
                  if ((geometry.width != 0) && (geometry.height != 0))
932
6.22k
                    {
933
6.22k
                      Image *resize_image = ResizeImage(next,geometry.width,
934
6.22k
                        geometry.height,next->filter,exception);
935
6.22k
                      if (resize_image != (Image *) NULL)
936
4.35k
                        ReplaceImageInList(&next,resize_image);
937
6.22k
                    }
938
7.81k
                }
939
11.0k
          }
940
12.8k
      }
941
221k
    profile=GetImageProfile(next,"icc");
942
221k
    if (profile == (const StringInfo *) NULL)
943
205k
      profile=GetImageProfile(next,"icm");
944
221k
    profile=GetImageProfile(next,"iptc");
945
221k
    if (profile == (const StringInfo *) NULL)
946
221k
      profile=GetImageProfile(next,"8bim");
947
221k
    if (IsSourceDataEpochSet() == MagickFalse)
948
221k
      {
949
221k
        char
950
221k
          timestamp[MagickTimeExtent];
951
952
221k
        (void) FormatMagickTime(next->timestamp,sizeof(timestamp),timestamp);
953
221k
        (void) SetImageProperty(next,"date:timestamp",timestamp,exception);
954
221k
        (void) FormatMagickTime((time_t) GetBlobProperties(next)->st_mtime,
955
221k
          sizeof(timestamp),timestamp);
956
221k
        (void) SetImageProperty(next,"date:modify",timestamp,exception);
957
221k
        (void) FormatMagickTime((time_t) GetBlobProperties(next)->st_ctime,
958
221k
          sizeof(timestamp),timestamp);
959
221k
        (void) SetImageProperty(next,"date:create",timestamp,exception);
960
221k
      }
961
221k
    if (constitute_info.delay_flags != NoValue)
962
0
      {
963
0
        if ((constitute_info.delay_flags & GreaterValue) != 0)
964
0
          {
965
0
            if (next->delay > constitute_info.delay)
966
0
              next->delay=constitute_info.delay;
967
0
          }
968
0
        else
969
0
          if ((constitute_info.delay_flags & LessValue) != 0)
970
0
            {
971
0
              if (next->delay < constitute_info.delay)
972
0
                next->delay=constitute_info.delay;
973
0
            }
974
0
          else
975
0
            next->delay=constitute_info.delay;
976
0
        if ((constitute_info.delay_flags & SigmaValue) != 0)
977
0
          next->ticks_per_second=constitute_info.ticks_per_second;
978
0
      }
979
221k
    if (constitute_info.dispose != (const char *) NULL)
980
0
      {
981
0
        ssize_t
982
0
          option_type;
983
984
0
        option_type=ParseCommandOption(MagickDisposeOptions,MagickFalse,
985
0
          constitute_info.dispose);
986
0
        if (option_type >= 0)
987
0
          next->dispose=(DisposeType) option_type;
988
0
      }
989
221k
    if (read_info->verbose != MagickFalse)
990
0
      (void) IdentifyImage(next,stderr,MagickFalse,exception);
991
221k
    image=next;
992
221k
  }
993
195k
  read_info=DestroyImageInfo(read_info);
994
195k
  if (GetBlobError(image) != MagickFalse)
995
195k
    ThrowReaderException(CorruptImageError,"UnableToReadImageData");
996
195k
  return(GetFirstImageInList(image));
997
195k
}
998
999
MagickExport Image *ReadImage(const ImageInfo *image_info,
1000
  ExceptionInfo *exception)
1001
878k
{
1002
878k
  return(ReadImageInternal(image_info,MagickTrue,exception));
1003
878k
}
1004

1005
/*
1006
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1007
%                                                                             %
1008
%                                                                             %
1009
%                                                                             %
1010
%   R e a d I m a g e W i t h o u t P o s t P r o c e s s i n g               %
1011
%                                                                             %
1012
%                                                                             %
1013
%                                                                             %
1014
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1015
%
1016
%  ReadImageWithoutPostProcessing() reads an intermediate image with format
1017
%  and source-dimension bookkeeping, leaving scene selection and final
1018
%  post-processing to the enclosing ReadImage() call.  On failure, a NULL
1019
%  image is returned and exception describes the reason for the failure.
1020
%
1021
%  The format of the ReadImageWithoutPostProcessing method is:
1022
%
1023
%      Image *ReadImageWithoutPostProcessing(const ImageInfo *image_info,
1024
%        ExceptionInfo *exception)
1025
%
1026
%  A description of each parameter follows:
1027
%
1028
%    o image_info: Read the image defined by the file or filename members of
1029
%      this structure.
1030
%
1031
%    o exception: return any errors or warnings in this structure.
1032
%
1033
*/
1034
MagickExport Image *ReadImageWithoutPostProcessing(const ImageInfo *image_info,
1035
  ExceptionInfo *exception)
1036
103
{
1037
103
  return(ReadImageInternal(image_info,MagickFalse,exception));
1038
103
}
1039

1040
/*
1041
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1042
%                                                                             %
1043
%                                                                             %
1044
%                                                                             %
1045
%   R e a d I m a g e s                                                       %
1046
%                                                                             %
1047
%                                                                             %
1048
%                                                                             %
1049
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1050
%
1051
%  ReadImages() reads one or more images and returns them as an image list.
1052
%
1053
%  The format of the ReadImage method is:
1054
%
1055
%      Image *ReadImages(ImageInfo *image_info,const char *filename,
1056
%        ExceptionInfo *exception)
1057
%
1058
%  A description of each parameter follows:
1059
%
1060
%    o image_info: the image info.
1061
%
1062
%    o filename: the image filename.
1063
%
1064
%    o exception: return any errors or warnings in this structure.
1065
%
1066
*/
1067
MagickExport Image *ReadImages(ImageInfo *image_info,const char *filename,
1068
  ExceptionInfo *exception)
1069
0
{
1070
0
  char
1071
0
    read_filename[MagickPathExtent];
1072
1073
0
  Image
1074
0
    *image,
1075
0
    *images;
1076
1077
0
  ImageInfo
1078
0
    *read_info;
1079
1080
  /*
1081
    Read image list from a file.
1082
  */
1083
0
  assert(image_info != (ImageInfo *) NULL);
1084
0
  assert(image_info->signature == MagickCoreSignature);
1085
0
  assert(exception != (ExceptionInfo *) NULL);
1086
0
  if (IsEventLogging() != MagickFalse)
1087
0
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1088
0
      image_info->filename);
1089
0
  read_info=CloneImageInfo(image_info);
1090
0
  *read_info->magick='\0';
1091
0
  (void) SetImageOption(read_info,"filename",filename);
1092
0
  (void) CopyMagickString(read_info->filename,filename,MagickPathExtent);
1093
0
  (void) InterpretImageFilename(read_info,(Image *) NULL,filename,
1094
0
    (int) read_info->scene,read_filename,exception);
1095
0
  if (LocaleCompare(read_filename,read_info->filename) != 0)
1096
0
    {
1097
0
      ExceptionInfo
1098
0
        *sans;
1099
1100
0
      ssize_t
1101
0
        extent,
1102
0
        scene;
1103
1104
      /*
1105
        Images of the form image-%d.png[1-5].
1106
      */
1107
0
      sans=AcquireExceptionInfo();
1108
0
      (void) SetImageInfo(read_info,0,sans);
1109
0
      sans=DestroyExceptionInfo(sans);
1110
0
      if (read_info->number_scenes != 0)
1111
0
        {
1112
0
          (void) CopyMagickString(read_filename,read_info->filename,
1113
0
            MagickPathExtent);
1114
0
          images=NewImageList();
1115
0
          extent=(ssize_t) (read_info->scene+read_info->number_scenes);
1116
0
          scene=(ssize_t) read_info->scene;
1117
0
          for ( ; scene < (ssize_t) extent; scene++)
1118
0
          {
1119
0
            (void) InterpretImageFilename(image_info,(Image *) NULL,
1120
0
              read_filename,(int) scene,read_info->filename,exception);
1121
0
            image=ReadImage(read_info,exception);
1122
0
            if (image == (Image *) NULL)
1123
0
              continue;
1124
0
            AppendImageToList(&images,image);
1125
0
          }
1126
0
          read_info=DestroyImageInfo(read_info);
1127
0
          return(images);
1128
0
        }
1129
0
    }
1130
0
  (void) CopyMagickString(read_info->filename,filename,MagickPathExtent);
1131
0
  image=ReadImage(read_info,exception);
1132
0
  read_info=DestroyImageInfo(read_info);
1133
0
  return(image);
1134
0
}
1135

1136
/*
1137
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1138
%                                                                             %
1139
%                                                                             %
1140
%                                                                             %
1141
+   R e a d I n l i n e I m a g e                                             %
1142
%                                                                             %
1143
%                                                                             %
1144
%                                                                             %
1145
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1146
%
1147
%  ReadInlineImage() reads a Base64-encoded inline image or image sequence.
1148
%  The method returns a NULL if there is a memory shortage or if the image
1149
%  cannot be read.  On failure, a NULL image is returned and exception
1150
%  describes the reason for the failure.
1151
%
1152
%  The format of the ReadInlineImage method is:
1153
%
1154
%      Image *ReadInlineImage(const ImageInfo *image_info,const char *content,
1155
%        ExceptionInfo *exception)
1156
%
1157
%  A description of each parameter follows:
1158
%
1159
%    o image_info: the image info.
1160
%
1161
%    o content: the image encoded in Base64.
1162
%
1163
%    o exception: return any errors or warnings in this structure.
1164
%
1165
*/
1166
1167
static MagickBooleanType GetImplicitDataImageType(const char *data_url,
1168
  char *magick,ExceptionInfo *exception)
1169
791
{
1170
791
  char
1171
791
    *plus;
1172
1173
791
  const char
1174
791
    *p,
1175
791
    *type,
1176
791
    *slash;
1177
1178
791
  const MagickInfo
1179
791
    *magick_info;
1180
1181
791
  size_t
1182
791
    offset;
1183
1184
791
  if (data_url == (const char *) NULL)
1185
0
    return(MagickFalse);
1186
791
  if (strncmp(data_url,"data:",5) != 0)
1187
0
    return(MagickFalse);
1188
791
  type=data_url+5;
1189
791
  p=type;
1190
89.6k
  while ((*p != '\0') && (*p != ';') && (*p != ','))
1191
88.8k
    p++;
1192
791
  if (p == type)
1193
0
    return(MagickFalse);
1194
791
  slash=(const char *) memchr(type,'/',(size_t) (p-type));
1195
791
  if ((slash == (const char *) NULL) || ((slash+1) >= p))
1196
0
    return(MagickFalse);
1197
791
  offset=(size_t) (p-(slash+1));
1198
791
  if (offset >= MagickPathExtent)
1199
0
    return(MagickFalse);
1200
791
  (void) memcpy(magick,slash+1,offset);
1201
791
  magick[offset]='\0';
1202
791
  plus=strchr(magick,'+');
1203
791
  if (plus != (char *) NULL)
1204
0
    *plus='\0';
1205
791
  if (LocaleNCompare(magick,"x-",2) == 0)
1206
0
    (void) memmove(magick,magick+2,strlen(magick+2)+1);
1207
791
  magick_info=GetMagickInfo(magick,exception);
1208
791
  if ((magick_info == (const MagickInfo *) NULL) ||
1209
791
      (magick_info->format_type == ImplicitFormatType))
1210
0
    return(MagickFalse);
1211
791
  return(MagickTrue);
1212
791
}
1213
1214
MagickExport Image *ReadInlineImage(const ImageInfo *image_info,
1215
  const char *content,ExceptionInfo *exception)
1216
826
{
1217
826
  const char
1218
826
    *p;
1219
1220
826
  Image
1221
826
    *image = (Image *) NULL;
1222
1223
826
  ImageInfo
1224
826
    *read_info;
1225
1226
826
  size_t
1227
826
    length;
1228
1229
826
  unsigned char
1230
826
    *blob;
1231
1232
  /*
1233
    Skip over header (e.g. data:image/gif;base64,).
1234
  */
1235
826
  image=NewImageList();
1236
289k
  for (p=content; (*p != ',') && (*p != '\0'); p++) ;
1237
826
  if (*p == '\0')
1238
793
    ThrowReaderException(CorruptImageError,"CorruptImage");
1239
793
  blob=Base64Decode(++p,&length);
1240
793
  if (length == 0)
1241
2
    {
1242
2
      blob=(unsigned char *) RelinquishMagickMemory(blob);
1243
2
      ThrowReaderException(CorruptImageError,"CorruptImage");
1244
0
    }
1245
791
  read_info=CloneImageInfo(image_info);
1246
791
  (void) SetImageInfoProgressMonitor(read_info,(MagickProgressMonitor) NULL,
1247
791
    (void *) NULL);
1248
791
  *read_info->filename='\0';
1249
791
  if (GetImplicitDataImageType(content,read_info->magick,exception) == MagickFalse)
1250
0
    {
1251
0
      blob=(unsigned char *) RelinquishMagickMemory(blob);
1252
0
      read_info=DestroyImageInfo(read_info);
1253
0
      ThrowReaderException(ImageError,"ImageTypeNotSupported");
1254
0
    }
1255
791
  image=BlobToImage(read_info,blob,length,exception);
1256
791
  blob=(unsigned char *) RelinquishMagickMemory(blob);
1257
791
  read_info=DestroyImageInfo(read_info);
1258
791
  return(image);
1259
791
}
1260

1261
/*
1262
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1263
%                                                                             %
1264
%                                                                             %
1265
%                                                                             %
1266
%   W r i t e I m a g e                                                       %
1267
%                                                                             %
1268
%                                                                             %
1269
%                                                                             %
1270
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1271
%
1272
%  WriteImage() writes an image or an image sequence to a file or file handle.
1273
%  If writing to a file is on disk, the name is defined by the filename member
1274
%  of the image structure.  WriteImage() returns MagickFalse is there is a
1275
%  memory shortage or if the image cannot be written.  Check the exception
1276
%  member of image to determine the cause for any failure.
1277
%
1278
%  The format of the WriteImage method is:
1279
%
1280
%      MagickBooleanType WriteImage(const ImageInfo *image_info,Image *image,
1281
%        ExceptionInfo *exception)
1282
%
1283
%  A description of each parameter follows:
1284
%
1285
%    o image_info: the image info.
1286
%
1287
%    o image: the image.
1288
%
1289
%    o exception: return any errors or warnings in this structure.
1290
%
1291
*/
1292
MagickExport MagickBooleanType WriteImage(const ImageInfo *image_info,
1293
  Image *image,ExceptionInfo *exception)
1294
63.0k
{
1295
63.0k
  char
1296
63.0k
    filename[MagickPathExtent];
1297
1298
63.0k
  const char
1299
63.0k
    *option;
1300
1301
63.0k
  const DelegateInfo
1302
63.0k
    *delegate_info;
1303
1304
63.0k
  const MagickInfo
1305
63.0k
    *magick_info;
1306
1307
63.0k
  EncodeImageHandler
1308
63.0k
    *encoder;
1309
1310
63.0k
  ExceptionInfo
1311
63.0k
    *sans_exception;
1312
1313
63.0k
  ImageInfo
1314
63.0k
    *write_info;
1315
1316
63.0k
  MagickBooleanType
1317
63.0k
    status,
1318
63.0k
    temporary;
1319
1320
  /*
1321
    Determine image type from filename prefix or suffix (e.g. image.jpg).
1322
  */
1323
63.0k
  assert(image_info != (ImageInfo *) NULL);
1324
63.0k
  assert(image_info->signature == MagickCoreSignature);
1325
63.0k
  assert(image != (Image *) NULL);
1326
63.0k
  if (IsEventLogging() != MagickFalse)
1327
0
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1328
0
      image_info->filename);
1329
63.0k
  assert(image->signature == MagickCoreSignature);
1330
63.0k
  assert(exception != (ExceptionInfo *) NULL);
1331
63.0k
  sans_exception=AcquireExceptionInfo();
1332
63.0k
  write_info=CloneImageInfo(image_info);
1333
63.0k
  (void) CopyMagickString(write_info->filename,image->filename,
1334
63.0k
    MagickPathExtent);
1335
63.0k
  (void) SetImageInfo(write_info,1,sans_exception);
1336
63.0k
  if (*write_info->magick == '\0')
1337
0
    (void) CopyMagickString(write_info->magick,image->magick,MagickPathExtent);
1338
63.0k
  (void) CopyMagickString(filename,image->filename,MagickPathExtent);
1339
63.0k
  (void) CopyMagickString(image->filename,write_info->filename,
1340
63.0k
    MagickPathExtent);
1341
  /*
1342
    Call appropriate image writer based on image type.
1343
  */
1344
63.0k
  magick_info=GetMagickInfo(write_info->magick,sans_exception);
1345
63.0k
  if (sans_exception->severity == PolicyError)
1346
0
    magick_info=GetMagickInfo(write_info->magick,exception);
1347
63.0k
  sans_exception=DestroyExceptionInfo(sans_exception);
1348
63.0k
  if (magick_info != (const MagickInfo *) NULL)
1349
63.0k
    {
1350
63.0k
      if (GetMagickEndianSupport(magick_info) == MagickFalse)
1351
55.3k
        image->endian=UndefinedEndian;
1352
7.66k
      else
1353
7.66k
        if ((image_info->endian == UndefinedEndian) &&
1354
7.66k
            (GetMagickRawSupport(magick_info) != MagickFalse))
1355
64
          image->endian=GetHostEndian();
1356
63.0k
    }
1357
63.0k
  if ((image->ping != MagickFalse) &&
1358
0
      (SyncImagePixelCache(image,exception) == MagickFalse))
1359
0
    {
1360
0
      write_info=DestroyImageInfo(write_info);
1361
0
      return(MagickFalse);
1362
0
    }
1363
63.0k
  SyncImageProfiles(image);
1364
63.0k
  DisassociateImageStream(image);
1365
63.0k
  option=GetImageOption(image_info,"delegate:bimodal");
1366
63.0k
  if ((IsStringTrue(option) != MagickFalse) &&
1367
0
      (write_info->page == (char *) NULL) &&
1368
0
      (GetPreviousImageInList(image) == (Image *) NULL) &&
1369
0
      (GetNextImageInList(image) == (Image *) NULL) &&
1370
0
      (IsTaintImage(image) == MagickFalse) )
1371
0
    {
1372
0
      delegate_info=GetDelegateInfo(image->magick,write_info->magick,exception);
1373
0
      if ((delegate_info != (const DelegateInfo *) NULL) &&
1374
0
          (GetDelegateMode(delegate_info) == 0) &&
1375
0
          (IsPathAccessible(image->magick_filename) != MagickFalse))
1376
0
        {
1377
          /*
1378
            Process image with bi-modal delegate.
1379
          */
1380
0
          (void) CopyMagickString(image->filename,image->magick_filename,
1381
0
            MagickPathExtent);
1382
0
          status=InvokeDelegate(write_info,image,image->magick,
1383
0
            write_info->magick,exception);
1384
0
          write_info=DestroyImageInfo(write_info);
1385
0
          (void) CopyMagickString(image->filename,filename,MagickPathExtent);
1386
0
          return(status);
1387
0
        }
1388
0
    }
1389
63.0k
  status=MagickFalse;
1390
63.0k
  temporary=MagickFalse;
1391
63.0k
  if ((magick_info != (const MagickInfo *) NULL) &&
1392
63.0k
      (GetMagickEncoderSeekableStream(magick_info) != MagickFalse))
1393
19.6k
    {
1394
19.6k
      char
1395
19.6k
        image_filename[MagickPathExtent];
1396
1397
19.6k
      (void) CopyMagickString(image_filename,image->filename,MagickPathExtent);
1398
19.6k
      status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
1399
19.6k
      (void) CopyMagickString(image->filename, image_filename,MagickPathExtent);
1400
19.6k
      if (status != MagickFalse)
1401
19.6k
        {
1402
19.6k
          if (IsBlobSeekable(image) == MagickFalse)
1403
0
            {
1404
              /*
1405
                A seekable stream is required by the encoder.
1406
              */
1407
0
              write_info->adjoin=MagickTrue;
1408
0
              (void) CopyMagickString(write_info->filename,image->filename,
1409
0
                MagickPathExtent);
1410
0
              (void) AcquireUniqueFilename(image->filename);
1411
0
              temporary=MagickTrue;
1412
0
            }
1413
19.6k
          if (CloseBlob(image) == MagickFalse)
1414
0
            status=MagickFalse;
1415
19.6k
        }
1416
19.6k
    }
1417
63.0k
  encoder=GetImageEncoder(magick_info);
1418
63.0k
  if (encoder != (EncodeImageHandler *) NULL)
1419
63.0k
    {
1420
      /*
1421
        Call appropriate image writer based on image type.
1422
      */
1423
63.0k
      if (GetMagickEncoderThreadSupport(magick_info) == MagickFalse)
1424
0
        LockSemaphoreInfo(magick_info->semaphore);
1425
63.0k
      status=IsCoderAuthorized(magick_info->magick_module,magick_info->name,
1426
63.0k
        WritePolicyRights,exception);
1427
63.0k
      if (status != MagickFalse)
1428
63.0k
        status=encoder(write_info,image,exception);
1429
63.0k
      if (GetMagickEncoderThreadSupport(magick_info) == MagickFalse)
1430
0
        UnlockSemaphoreInfo(magick_info->semaphore);
1431
63.0k
    }
1432
0
  else
1433
0
    {
1434
0
      delegate_info=GetDelegateInfo((char *) NULL,write_info->magick,exception);
1435
0
      if (delegate_info != (DelegateInfo *) NULL)
1436
0
        {
1437
          /*
1438
            Process the image with delegate.
1439
          */
1440
0
          *write_info->filename='\0';
1441
0
          if (GetDelegateThreadSupport(delegate_info) == MagickFalse)
1442
0
            LockSemaphoreInfo(delegate_info->semaphore);
1443
0
          status=InvokeDelegate(write_info,image,(char *) NULL,
1444
0
            write_info->magick,exception);
1445
0
          if (GetDelegateThreadSupport(delegate_info) == MagickFalse)
1446
0
            UnlockSemaphoreInfo(delegate_info->semaphore);
1447
0
          (void) CopyMagickString(image->filename,filename,MagickPathExtent);
1448
0
        }
1449
0
      else
1450
0
        {
1451
0
          sans_exception=AcquireExceptionInfo();
1452
0
          magick_info=GetMagickInfo(write_info->magick,sans_exception);
1453
0
          if (sans_exception->severity == PolicyError)
1454
0
            magick_info=GetMagickInfo(write_info->magick,exception);
1455
0
          sans_exception=DestroyExceptionInfo(sans_exception);
1456
0
          if ((write_info->affirm == MagickFalse) &&
1457
0
              (magick_info == (const MagickInfo *) NULL))
1458
0
            {
1459
0
              (void) CopyMagickString(write_info->magick,image->magick,
1460
0
                MagickPathExtent);
1461
0
              magick_info=GetMagickInfo(write_info->magick,exception);
1462
0
            }
1463
0
          encoder=GetImageEncoder(magick_info);
1464
0
          if (encoder == (EncodeImageHandler *) NULL)
1465
0
            {
1466
0
              char
1467
0
                extension[MagickPathExtent];
1468
1469
0
              GetPathComponent(image->filename,ExtensionPath,extension);
1470
0
              if (*extension != '\0')
1471
0
                magick_info=GetMagickInfo(extension,exception);
1472
0
              else
1473
0
                magick_info=GetMagickInfo(image->magick,exception);
1474
0
              (void) CopyMagickString(image->filename,filename,
1475
0
                MagickPathExtent);
1476
0
              encoder=GetImageEncoder(magick_info);
1477
0
              (void) ThrowMagickException(exception,GetMagickModule(),
1478
0
                MissingDelegateWarning,"NoEncodeDelegateForThisImageFormat",
1479
0
                "`%s'",write_info->magick);
1480
0
            }
1481
0
          if (encoder == (EncodeImageHandler *) NULL)
1482
0
            {
1483
0
              magick_info=GetMagickInfo(image->magick,exception);
1484
0
              encoder=GetImageEncoder(magick_info);
1485
0
              if (encoder == (EncodeImageHandler *) NULL)
1486
0
                (void) ThrowMagickException(exception,GetMagickModule(),
1487
0
                  MissingDelegateError,"NoEncodeDelegateForThisImageFormat",
1488
0
                  "`%s'",write_info->magick);
1489
0
            }
1490
0
          if (encoder != (EncodeImageHandler *) NULL)
1491
0
            {
1492
              /*
1493
                Call appropriate image writer based on image type.
1494
              */
1495
0
              if (GetMagickEncoderThreadSupport(magick_info) == MagickFalse)
1496
0
                LockSemaphoreInfo(magick_info->semaphore);
1497
0
              status=IsCoderAuthorized(magick_info->magick_module,magick_info->name,
1498
0
                WritePolicyRights,exception);
1499
0
              if (status != MagickFalse)
1500
0
                status=encoder(write_info,image,exception);
1501
0
              if (GetMagickEncoderThreadSupport(magick_info) == MagickFalse)
1502
0
                UnlockSemaphoreInfo(magick_info->semaphore);
1503
0
            }
1504
0
        }
1505
0
    }
1506
63.0k
  if (temporary != MagickFalse)
1507
0
    {
1508
      /*
1509
        Copy temporary image file to permanent.
1510
      */
1511
0
      status=OpenBlob(write_info,image,ReadBinaryBlobMode,exception);
1512
0
      if (status != MagickFalse)
1513
0
        {
1514
0
          (void) RelinquishUniqueFileResource(write_info->filename);
1515
0
          status=ImageToFile(image,write_info->filename,exception);
1516
0
        }
1517
0
      if (CloseBlob(image) == MagickFalse)
1518
0
        status=MagickFalse;
1519
0
      (void) RelinquishUniqueFileResource(image->filename);
1520
0
      (void) CopyMagickString(image->filename,write_info->filename,
1521
0
        MagickPathExtent);
1522
0
    }
1523
63.0k
  if ((LocaleCompare(write_info->magick,"info") != 0) &&
1524
63.0k
      (write_info->verbose != MagickFalse))
1525
0
    (void) IdentifyImage(image,stdout,MagickFalse,exception);
1526
63.0k
  write_info=DestroyImageInfo(write_info);
1527
63.0k
  if (GetBlobError(image) != MagickFalse)
1528
63.0k
    ThrowWriterException(FileOpenError,"UnableToWriteFile");
1529
63.0k
  return(status);
1530
63.0k
}
1531

1532
/*
1533
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1534
%                                                                             %
1535
%                                                                             %
1536
%                                                                             %
1537
%   W r i t e I m a g e s                                                     %
1538
%                                                                             %
1539
%                                                                             %
1540
%                                                                             %
1541
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1542
%
1543
%  WriteImages() writes an image sequence into one or more files.  While
1544
%  WriteImage() can write an image sequence, it is limited to writing
1545
%  the sequence into a single file using a format which supports multiple
1546
%  frames.   WriteImages(), however, does not have this limitation, instead it
1547
%  generates multiple output files if necessary (or when requested).  When
1548
%  ImageInfo's adjoin flag is set to MagickFalse, the file name is expected
1549
%  to include a printf-style formatting string for the frame number (e.g.
1550
%  "image%02d.png").
1551
%
1552
%  The format of the WriteImages method is:
1553
%
1554
%      MagickBooleanType WriteImages(const ImageInfo *image_info,Image *images,
1555
%        const char *filename,ExceptionInfo *exception)
1556
%
1557
%  A description of each parameter follows:
1558
%
1559
%    o image_info: the image info.
1560
%
1561
%    o images: the image list.
1562
%
1563
%    o filename: the image filename.
1564
%
1565
%    o exception: return any errors or warnings in this structure.
1566
%
1567
*/
1568
MagickExport MagickBooleanType WriteImages(const ImageInfo *image_info,
1569
  Image *images,const char *filename,ExceptionInfo *exception)
1570
37.9k
{
1571
37.9k
#define WriteImageTag  "Write/Image"
1572
1573
37.9k
  ExceptionInfo
1574
37.9k
    *sans_exception;
1575
1576
37.9k
  ImageInfo
1577
37.9k
    *write_info;
1578
1579
37.9k
  MagickBooleanType
1580
37.9k
    proceed;
1581
1582
37.9k
  MagickOffsetType
1583
37.9k
    progress;
1584
1585
37.9k
  MagickProgressMonitor
1586
37.9k
    progress_monitor;
1587
1588
37.9k
  MagickSizeType
1589
37.9k
    number_images;
1590
1591
37.9k
  MagickStatusType
1592
37.9k
    status;
1593
1594
37.9k
  Image
1595
37.9k
    *p;
1596
1597
37.9k
  assert(image_info != (const ImageInfo *) NULL);
1598
37.9k
  assert(image_info->signature == MagickCoreSignature);
1599
37.9k
  assert(images != (Image *) NULL);
1600
37.9k
  assert(images->signature == MagickCoreSignature);
1601
37.9k
  if (IsEventLogging() != MagickFalse)
1602
0
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
1603
37.9k
  assert(exception != (ExceptionInfo *) NULL);
1604
37.9k
  write_info=CloneImageInfo(image_info);
1605
37.9k
  *write_info->magick='\0';
1606
37.9k
  images=GetFirstImageInList(images);
1607
37.9k
  if (images == (Image *) NULL)
1608
0
    return(MagickFalse);
1609
37.9k
  if (filename != (const char *) NULL)
1610
75.8k
    for (p=images; p != (Image *) NULL; p=GetNextImageInList(p))
1611
37.9k
      (void) CopyMagickString(p->filename,filename,MagickPathExtent);
1612
37.9k
  (void) CopyMagickString(write_info->filename,images->filename,
1613
37.9k
    MagickPathExtent);
1614
37.9k
  sans_exception=AcquireExceptionInfo();
1615
37.9k
  (void) SetImageInfo(write_info,(unsigned int) GetImageListLength(images),
1616
37.9k
    sans_exception);
1617
37.9k
  sans_exception=DestroyExceptionInfo(sans_exception);
1618
37.9k
  if (*write_info->magick == '\0')
1619
36.0k
    (void) CopyMagickString(write_info->magick,images->magick,MagickPathExtent);
1620
37.9k
  p=images;
1621
37.9k
  for ( ; GetNextImageInList(p) != (Image *) NULL; p=GetNextImageInList(p))
1622
0
  {
1623
0
    if (p->scene >= GetNextImageInList(p)->scene)
1624
0
      {
1625
0
        ssize_t
1626
0
          i;
1627
1628
        /*
1629
          Generate consistent scene numbers.
1630
        */
1631
0
        i=(ssize_t) images->scene;
1632
0
        for (p=images; p != (Image *) NULL; p=GetNextImageInList(p))
1633
0
          p->scene=(size_t) i++;
1634
0
        break;
1635
0
      }
1636
0
  }
1637
  /*
1638
    Write images.
1639
  */
1640
37.9k
  status=MagickTrue;
1641
37.9k
  progress_monitor=(MagickProgressMonitor) NULL;
1642
37.9k
  progress=0;
1643
37.9k
  number_images=GetImageListLength(images);
1644
37.9k
  for (p=images; p != (Image *) NULL; p=GetNextImageInList(p))
1645
37.9k
  {
1646
37.9k
    if (number_images != 1)
1647
0
      progress_monitor=SetImageProgressMonitor(p,(MagickProgressMonitor) NULL,
1648
0
        p->client_data);
1649
37.9k
    status&=(MagickStatusType) WriteImage(write_info,p,exception);
1650
37.9k
    if (write_info->blob != (void *) NULL)
1651
36.0k
      SyncBlobStream(write_info,p,images);
1652
37.9k
    if (number_images != 1)
1653
0
      (void) SetImageProgressMonitor(p,progress_monitor,p->client_data);
1654
37.9k
    if (write_info->adjoin != MagickFalse)
1655
37.9k
      break;
1656
0
    if (number_images != 1)
1657
0
      {
1658
#if defined(MAGICKCORE_OPENMP_SUPPORT)
1659
        #pragma omp atomic
1660
#endif
1661
0
        progress++;
1662
0
        proceed=SetImageProgress(p,WriteImageTag,progress,number_images);
1663
0
        if (proceed == MagickFalse)
1664
0
          break;
1665
0
      }
1666
0
  }
1667
37.9k
  write_info=DestroyImageInfo(write_info);
1668
37.9k
  return(status != 0 ? MagickTrue : MagickFalse);
1669
37.9k
}