Coverage Report

Created: 2026-09-13 07:02

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
0
{
170
0
  Image
171
0
    *image;
172
173
0
  MagickBooleanType
174
0
    status;
175
176
0
  ssize_t
177
0
    i;
178
179
0
  size_t
180
0
    length;
181
182
  /*
183
    Allocate image structure.
184
  */
185
0
  assert(map != (const char *) NULL);
186
0
  assert(pixels != (void *) NULL);
187
0
  assert(exception != (ExceptionInfo *) NULL);
188
0
  assert(exception->signature == MagickCoreSignature);
189
0
  if (IsEventLogging() != MagickFalse)
190
0
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",map);
191
0
  image=AcquireImage((ImageInfo *) NULL,exception);
192
0
  if (image == (Image *) NULL)
193
0
    return((Image *) NULL);
194
0
  switch (storage)
195
0
  {
196
0
    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
0
  }
204
0
  length=strlen(map);
205
0
  for (i=0; i < (ssize_t) length; i++)
206
0
  {
207
0
    switch (map[i])
208
0
    {
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
0
      default:
236
0
      {
237
0
        if (length == 1)
238
0
          image->colorspace=GRAYColorspace;
239
0
        break;
240
0
      }
241
0
    }
242
0
  }
243
0
  status=SetImageExtent(image,columns,rows,exception);
244
0
  if (status == MagickFalse)
245
0
    return(DestroyImageList(image));
246
0
  status=ResetImagePixels(image,exception);
247
0
  if (status == MagickFalse)
248
0
    return(DestroyImageList(image));
249
0
  status=ImportImagePixels(image,0,0,columns,rows,map,storage,pixels,exception);
250
0
  if (status == MagickFalse)
251
0
    image=DestroyImage(image);
252
0
  return(image);
253
0
}
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
808k
{
455
808k
  if (IsRightsAuthorized(CoderPolicyDomain,rights,coder) == MagickFalse)
456
808k
    ThrowPolicyException(coder,MagickFalse);
457
808k
  if (IsRightsAuthorized(ModulePolicyDomain,rights,module) == MagickFalse)
458
808k
    ThrowPolicyException(module,MagickFalse);
459
808k
  return(MagickTrue);
460
808k
}
461
462
static void InitializeConstituteInfo(const ImageInfo *image_info,
463
  ConstituteInfo *constitute_info)
464
289k
{
465
289k
  const char
466
289k
    *option;
467
468
289k
  memset(constitute_info,0,sizeof(*constitute_info));
469
289k
  constitute_info->sync_from_exif=MagickTrue;
470
289k
  constitute_info->sync_from_tiff=MagickTrue;
471
289k
  option=GetImageOption(image_info,"exif:sync-image");
472
289k
  if (IsStringFalse(option) != MagickFalse)
473
0
    constitute_info->sync_from_exif=MagickFalse;
474
289k
  option=GetImageOption(image_info,"tiff:sync-image");
475
289k
  if (IsStringFalse(option) != MagickFalse)
476
0
    constitute_info->sync_from_tiff=MagickFalse;
477
289k
  constitute_info->caption=GetImageOption(image_info,"caption");
478
289k
  constitute_info->comment=GetImageOption(image_info,"comment");
479
289k
  constitute_info->label=GetImageOption(image_info,"label");
480
289k
  option=GetImageOption(image_info,"delay");
481
289k
  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
289k
}
496
497
static void SyncOrientationFromProperties(Image *image,
498
  ConstituteInfo *constitute_info,ExceptionInfo *exception)
499
333k
{
500
333k
  const char
501
333k
    *orientation;
502
503
333k
  orientation=(const char *) NULL;
504
333k
  if (constitute_info->sync_from_exif != MagickFalse)
505
333k
    {
506
333k
      orientation=GetImageProperty(image,"exif:Orientation",exception);
507
333k
      if (orientation != (const char *) NULL)
508
3.29k
        {
509
3.29k
          image->orientation=(OrientationType) StringToLong(orientation);
510
3.29k
          (void) DeleteImageProperty(image,"exif:Orientation");
511
3.29k
        }
512
333k
    }
513
333k
  if ((orientation == (const char *) NULL) &&
514
330k
      (constitute_info->sync_from_tiff != MagickFalse))
515
330k
    {
516
330k
      orientation=GetImageProperty(image,"tiff:Orientation",exception);
517
330k
      if (orientation != (const char *) NULL)
518
0
        {
519
0
          image->orientation=(OrientationType) StringToLong(orientation);
520
0
          (void) DeleteImageProperty(image,"tiff:Orientation");
521
0
        }
522
330k
    }
523
333k
}
524
525
static void SyncResolutionFromProperties(Image *image,
526
  ConstituteInfo *constitute_info, ExceptionInfo *exception)
527
333k
{
528
333k
  const char
529
333k
    *resolution_x,
530
333k
    *resolution_y,
531
333k
    *resolution_units;
532
533
333k
  MagickBooleanType
534
333k
    used_tiff;
535
536
333k
  resolution_x=(const char *) NULL;
537
333k
  resolution_y=(const char *) NULL;
538
333k
  resolution_units=(const char *) NULL;
539
333k
  used_tiff=MagickFalse;
540
333k
  if (constitute_info->sync_from_exif != MagickFalse)
541
333k
    {
542
333k
      resolution_x=GetImageProperty(image,"exif:XResolution",exception);
543
333k
      resolution_y=GetImageProperty(image,"exif:YResolution",exception);
544
333k
      if ((resolution_x != (const char *) NULL) &&
545
12.3k
          (resolution_y != (const char *) NULL))
546
10.7k
        resolution_units=GetImageProperty(image,"exif:ResolutionUnit",
547
10.7k
          exception);
548
333k
    }
549
333k
  if ((resolution_x == (const char *) NULL) &&
550
321k
      (resolution_y == (const char *) NULL) &&
551
319k
      (constitute_info->sync_from_tiff != MagickFalse))
552
319k
    {
553
319k
      resolution_x=GetImageProperty(image,"tiff:XResolution",exception);
554
319k
      resolution_y=GetImageProperty(image,"tiff:YResolution",exception);
555
319k
      if ((resolution_x != (const char *) NULL) &&
556
117
          (resolution_y != (const char *) NULL))
557
117
        {
558
117
          used_tiff=MagickTrue;
559
117
          resolution_units=GetImageProperty(image,"tiff:ResolutionUnit",
560
117
            exception);
561
117
        }
562
319k
    }
563
333k
  if ((resolution_x != (const char *) NULL) &&
564
12.4k
      (resolution_y != (const char *) NULL))
565
10.8k
    {
566
10.8k
      GeometryInfo
567
10.8k
        geometry_info;
568
569
10.8k
      ssize_t
570
10.8k
        option_type;
571
572
10.8k
      geometry_info.rho=image->resolution.x;
573
10.8k
      geometry_info.sigma=1.0;
574
10.8k
      (void) ParseGeometry(resolution_x,&geometry_info);
575
10.8k
      if (geometry_info.sigma != 0)
576
3.78k
        image->resolution.x=geometry_info.rho/geometry_info.sigma;
577
10.8k
      if (strchr(resolution_x,',') != (char *) NULL)
578
2.73k
        image->resolution.x=geometry_info.rho+geometry_info.sigma/1000.0;
579
10.8k
      geometry_info.rho=image->resolution.y;
580
10.8k
      geometry_info.sigma=1.0;
581
10.8k
      (void) ParseGeometry(resolution_y,&geometry_info);
582
10.8k
      if (geometry_info.sigma != 0)
583
3.62k
        image->resolution.y=geometry_info.rho/geometry_info.sigma;
584
10.8k
      if (strchr(resolution_y,',') != (char *) NULL)
585
2.99k
        image->resolution.y=geometry_info.rho+geometry_info.sigma/1000.0;
586
10.8k
      if (resolution_units != (char *) NULL)
587
2.28k
        {
588
2.28k
          option_type=ParseCommandOption(MagickResolutionOptions,MagickFalse,
589
2.28k
            resolution_units);
590
2.28k
          if (option_type >= 0)
591
326
            image->units=(ResolutionType) option_type;
592
2.28k
        }
593
10.8k
      if (used_tiff == MagickFalse)
594
10.7k
        {
595
10.7k
          (void) DeleteImageProperty(image,"exif:XResolution");
596
10.7k
          (void) DeleteImageProperty(image,"exif:YResolution");
597
10.7k
          (void) DeleteImageProperty(image,"exif:ResolutionUnit");
598
10.7k
        }
599
117
      else
600
117
        {
601
117
          (void) DeleteImageProperty(image,"tiff:XResolution");
602
117
          (void) DeleteImageProperty(image,"tiff:YResolution");
603
117
          (void) DeleteImageProperty(image,"tiff:ResolutionUnit");
604
117
        }
605
10.8k
    }
606
333k
}
607
608
MagickExport Image *ReadImage(const ImageInfo *image_info,
609
  ExceptionInfo *exception)
610
747k
{
611
747k
  char
612
747k
    filename[MagickPathExtent],
613
747k
    magick[MagickPathExtent],
614
747k
    magick_filename[MagickPathExtent];
615
616
747k
  ConstituteInfo
617
747k
    constitute_info;
618
619
747k
  const DelegateInfo
620
747k
    *delegate_info;
621
622
747k
  const MagickInfo
623
747k
    *magick_info;
624
625
747k
  DecodeImageHandler
626
747k
    *decoder;
627
628
747k
  ExceptionInfo
629
747k
    *sans_exception;
630
631
747k
  Image
632
747k
    *image,
633
747k
    *next;
634
635
747k
  ImageInfo
636
747k
    *read_info;
637
638
747k
  MagickBooleanType
639
747k
    status;
640
641
  /*
642
    Determine image type from filename prefix or suffix (e.g. image.jpg).
643
  */
644
747k
  assert(image_info != (ImageInfo *) NULL);
645
747k
  assert(image_info->signature == MagickCoreSignature);
646
747k
  assert(image_info->filename != (char *) NULL);
647
747k
  if (IsEventLogging() != MagickFalse)
648
0
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
649
0
      image_info->filename);
650
747k
  assert(exception != (ExceptionInfo *) NULL);
651
747k
  read_info=CloneImageInfo(image_info);
652
747k
  (void) CopyMagickString(magick_filename,read_info->filename,MagickPathExtent);
653
747k
  (void) SetImageInfo(read_info,0,exception);
654
747k
  (void) CopyMagickString(filename,read_info->filename,MagickPathExtent);
655
747k
  (void) CopyMagickString(magick,read_info->magick,MagickPathExtent);
656
  /*
657
    Call appropriate image reader based on image type.
658
  */
659
747k
  sans_exception=AcquireExceptionInfo();
660
747k
  magick_info=GetMagickInfo(read_info->magick,sans_exception);
661
747k
  if (sans_exception->severity == PolicyError)
662
0
    InheritException(exception,sans_exception);
663
747k
  sans_exception=DestroyExceptionInfo(sans_exception);
664
747k
  if (magick_info != (const MagickInfo *) NULL)
665
746k
    {
666
746k
      if (GetMagickEndianSupport(magick_info) == MagickFalse)
667
629k
        read_info->endian=UndefinedEndian;
668
117k
      else
669
117k
        if ((image_info->endian == UndefinedEndian) &&
670
117k
            (GetMagickRawSupport(magick_info) != MagickFalse))
671
8.82k
          read_info->endian=GetHostEndian();
672
746k
    }
673
747k
  if ((magick_info != (const MagickInfo *) NULL) &&
674
746k
      (GetMagickDecoderSeekableStream(magick_info) != MagickFalse))
675
611k
    {
676
611k
      image=AcquireImage(read_info,exception);
677
611k
      (void) CopyMagickString(image->filename,read_info->filename,
678
611k
        MagickPathExtent);
679
611k
      status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
680
611k
      if (status == MagickFalse)
681
26
        {
682
26
          read_info=DestroyImageInfo(read_info);
683
26
          image=DestroyImage(image);
684
26
          return((Image *) NULL);
685
26
        }
686
611k
      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
611k
      (void) CloseBlob(image);
703
611k
      image=DestroyImage(image);
704
611k
    }
705
746k
  image=NewImageList();
706
746k
  decoder=GetImageDecoder(magick_info);
707
746k
  if (decoder == (DecodeImageHandler *) NULL)
708
268
    {
709
268
      delegate_info=GetDelegateInfo(read_info->magick,(char *) NULL,exception);
710
268
      if (delegate_info == (const DelegateInfo *) NULL)
711
268
        {
712
268
          (void) SetImageInfo(read_info,0,exception);
713
268
          (void) CopyMagickString(read_info->filename,filename,
714
268
            MagickPathExtent);
715
268
          magick_info=GetMagickInfo(read_info->magick,exception);
716
268
          decoder=GetImageDecoder(magick_info);
717
268
        }
718
268
    }
719
746k
  if (decoder != (DecodeImageHandler *) NULL)
720
746k
    {
721
      /*
722
        Call appropriate image reader based on image type.
723
      */
724
746k
      if (GetMagickDecoderThreadSupport(magick_info) == MagickFalse)
725
662
        LockSemaphoreInfo(magick_info->semaphore);
726
746k
      status=IsCoderAuthorized(magick_info->magick_module,magick_info->name,
727
746k
        ReadPolicyRights,exception);
728
746k
      image=(Image *) NULL;
729
746k
      if (status != MagickFalse)
730
746k
        image=decoder(read_info,exception);
731
746k
      if (GetMagickDecoderThreadSupport(magick_info) == MagickFalse)
732
662
        UnlockSemaphoreInfo(magick_info->semaphore);
733
746k
    }
734
268
  else
735
268
    {
736
268
      delegate_info=GetDelegateInfo(read_info->magick,(char *) NULL,exception);
737
268
      if (delegate_info == (const DelegateInfo *) NULL)
738
268
        {
739
268
          (void) ThrowMagickException(exception,GetMagickModule(),
740
268
            MissingDelegateError,"NoDecodeDelegateForThisImageFormat","`%s'",
741
268
            read_info->filename);
742
268
          if (read_info->temporary != MagickFalse)
743
257
            (void) RelinquishUniqueFileResource(read_info->filename);
744
268
          read_info=DestroyImageInfo(read_info);
745
268
          return((Image *) NULL);
746
268
        }
747
      /*
748
        Let our decoding delegate process the image.
749
      */
750
0
      image=AcquireImage(read_info,exception);
751
0
      if (image == (Image *) NULL)
752
0
        {
753
0
          read_info=DestroyImageInfo(read_info);
754
0
          return((Image *) NULL);
755
0
        }
756
0
      (void) CopyMagickString(image->filename,read_info->filename,
757
0
        MagickPathExtent);
758
0
      *read_info->filename='\0';
759
0
      if (GetDelegateThreadSupport(delegate_info) == MagickFalse)
760
0
        LockSemaphoreInfo(delegate_info->semaphore);
761
0
      status=InvokeDelegate(read_info,image,read_info->magick,(char *) NULL,
762
0
        exception);
763
0
      if (GetDelegateThreadSupport(delegate_info) == MagickFalse)
764
0
        UnlockSemaphoreInfo(delegate_info->semaphore);
765
0
      image=DestroyImageList(image);
766
0
      read_info->temporary=MagickTrue;
767
0
      if (status != MagickFalse)
768
0
        (void) SetImageInfo(read_info,0,exception);
769
0
      magick_info=GetMagickInfo(read_info->magick,exception);
770
0
      decoder=GetImageDecoder(magick_info);
771
0
      if (decoder == (DecodeImageHandler *) NULL)
772
0
        {
773
0
          if (IsPathAccessible(read_info->filename) != MagickFalse)
774
0
            (void) ThrowMagickException(exception,GetMagickModule(),
775
0
              MissingDelegateError,"NoDecodeDelegateForThisImageFormat","`%s'",
776
0
              read_info->magick);
777
0
          else
778
0
            ThrowFileException(exception,FileOpenError,"UnableToOpenFile",
779
0
              read_info->filename);
780
0
          read_info=DestroyImageInfo(read_info);
781
0
          return((Image *) NULL);
782
0
        }
783
      /*
784
        Call appropriate image reader based on image type.
785
      */
786
0
      if (GetMagickDecoderThreadSupport(magick_info) == MagickFalse)
787
0
        LockSemaphoreInfo(magick_info->semaphore);
788
0
      status=IsCoderAuthorized(magick_info->magick_module,magick_info->name,
789
0
        ReadPolicyRights,exception);
790
0
      image=(Image *) NULL;
791
0
      if (status != MagickFalse)
792
0
        image=(decoder)(read_info,exception);
793
0
      if (GetMagickDecoderThreadSupport(magick_info) == MagickFalse)
794
0
        UnlockSemaphoreInfo(magick_info->semaphore);
795
0
    }
796
746k
  if (read_info->temporary != MagickFalse)
797
29
    {
798
29
      (void) RelinquishUniqueFileResource(read_info->filename);
799
29
      read_info->temporary=MagickFalse;
800
29
      if (image != (Image *) NULL)
801
0
        (void) CopyMagickString(image->filename,filename,MagickPathExtent);
802
29
    }
803
746k
  if (image == (Image *) NULL)
804
457k
    {
805
457k
      read_info=DestroyImageInfo(read_info);
806
457k
      return(image);
807
457k
    }
808
289k
  if (exception->severity >= ErrorException)
809
100k
    (void) LogMagickEvent(ExceptionEvent,GetMagickModule(),
810
100k
      "Coder (%s) generated an image despite an error (%d), "
811
100k
      "notify the developers",image->magick,exception->severity);
812
289k
  if (IsBlobTemporary(image) != MagickFalse)
813
0
    (void) RelinquishUniqueFileResource(read_info->filename);
814
289k
  if (read_info->ping != MagickFalse)
815
10.8k
    {
816
24.0k
      for (next=image; next != (Image *) NULL; next=GetNextImageInList(next))
817
13.2k
      {
818
13.2k
        if ((image->columns == 0) || (image->rows == 0))
819
34
          {
820
34
            read_info=DestroyImageInfo(read_info);
821
34
            ThrowReaderException(ImageError,"NegativeOrZeroImageSize");
822
0
          }
823
13.2k
      }
824
10.8k
    }
825
289k
  if ((IsSceneGeometry(read_info->scenes,MagickFalse) != MagickFalse) &&
826
2.22k
      (GetImageListLength(image) != 1))
827
0
    {
828
0
      Image
829
0
        *clones;
830
831
0
      clones=CloneImages(image,read_info->scenes,exception);
832
0
      image=DestroyImageList(image);
833
0
      if (clones != (Image *) NULL)
834
0
        image=GetFirstImageInList(clones);
835
0
      if (image == (Image *) NULL)
836
0
        {
837
0
          read_info=DestroyImageInfo(read_info);
838
0
          return(image);
839
0
        }
840
0
    }
841
289k
  InitializeConstituteInfo(read_info,&constitute_info);
842
622k
  for (next=image; next != (Image *) NULL; next=GetNextImageInList(next))
843
333k
  {
844
333k
    char
845
333k
      magick_path[MagickPathExtent],
846
333k
      *property;
847
848
333k
    const StringInfo
849
333k
      *profile;
850
851
333k
    next->taint=MagickFalse;
852
333k
    GetPathComponent(magick_filename,MagickPath,magick_path);
853
333k
    if ((*magick_path == '\0') && (*next->magick == '\0'))
854
0
      (void) CopyMagickString(next->magick,magick,MagickPathExtent);
855
333k
    (void) CopyMagickString(next->magick_filename,magick_filename,
856
333k
      MagickPathExtent);
857
333k
    if (IsBlobTemporary(image) != MagickFalse)
858
0
      (void) CopyMagickString(next->filename,filename,MagickPathExtent);
859
333k
    if (next->magick_columns == 0)
860
303k
      next->magick_columns=next->columns;
861
333k
    if (next->magick_rows == 0)
862
303k
      next->magick_rows=next->rows;
863
333k
    (void) GetImageProperty(next,"exif:*",exception);
864
333k
    (void) GetImageProperty(next,"icc:*",exception);
865
333k
    (void) GetImageProperty(next,"iptc:*",exception);
866
333k
    (void) GetImageProperty(next,"xmp:*",exception);
867
333k
    SyncOrientationFromProperties(next,&constitute_info,exception);
868
333k
    SyncResolutionFromProperties(next,&constitute_info,exception);
869
333k
    if (next->page.width == 0)
870
275k
      next->page.width=next->columns;
871
333k
    if (next->page.height == 0)
872
276k
      next->page.height=next->rows;
873
333k
    if (constitute_info.caption != (const char *) NULL)
874
0
      {
875
0
        property=InterpretImageProperties(read_info,next,
876
0
          constitute_info.caption,exception);
877
0
        (void) SetImageProperty(next,"caption",property,exception);
878
0
        property=DestroyString(property);
879
0
      }
880
333k
    if (constitute_info.comment != (const char *) NULL)
881
0
      {
882
0
        property=InterpretImageProperties(read_info,next,
883
0
          constitute_info.comment,exception);
884
0
        (void) SetImageProperty(next,"comment",property,exception);
885
0
        property=DestroyString(property);
886
0
      }
887
333k
    if (constitute_info.label != (const char *) NULL)
888
0
      {
889
0
        property=InterpretImageProperties(read_info,next,
890
0
          constitute_info.label,exception);
891
0
        (void) SetImageProperty(next,"label",property,exception);
892
0
        property=DestroyString(property);
893
0
      }
894
333k
    if (LocaleCompare(next->magick,"TEXT") == 0)
895
0
      (void) ParseAbsoluteGeometry("0x0+0+0",&next->page);
896
333k
    if ((read_info->extract != (char *) NULL) &&
897
14.3k
        (read_info->stream == (StreamHandler) NULL))
898
14.3k
      {
899
14.3k
        RectangleInfo
900
14.3k
          geometry;
901
902
14.3k
        MagickStatusType
903
14.3k
          flags;
904
905
14.3k
        SetGeometry(next,&geometry);
906
14.3k
        flags=ParseAbsoluteGeometry(read_info->extract,&geometry);
907
14.3k
        if ((next->columns != geometry.width) ||
908
2.92k
            (next->rows != geometry.height))
909
12.5k
          {
910
12.5k
            if (((flags & XValue) != 0) || ((flags & YValue) != 0))
911
3.37k
              {
912
3.37k
                Image *crop_image = CropImage(next,&geometry,exception);
913
3.37k
                if (crop_image != (Image *) NULL)
914
2.05k
                  ReplaceImageInList(&next,crop_image);
915
3.37k
              }
916
9.22k
            else
917
9.22k
              if (((flags & WidthValue) != 0) || ((flags & HeightValue) != 0))
918
8.85k
                {
919
8.85k
                  flags=ParseRegionGeometry(next,read_info->extract,&geometry,
920
8.85k
                    exception);
921
8.85k
                  if ((geometry.width != 0) && (geometry.height != 0))
922
7.28k
                    {
923
7.28k
                      Image *resize_image = ResizeImage(next,geometry.width,
924
7.28k
                        geometry.height,next->filter,exception);
925
7.28k
                      if (resize_image != (Image *) NULL)
926
4.49k
                        ReplaceImageInList(&next,resize_image);
927
7.28k
                    }
928
8.85k
                }
929
12.5k
          }
930
14.3k
      }
931
333k
    profile=GetImageProfile(next,"icc");
932
333k
    if (profile == (const StringInfo *) NULL)
933
306k
      profile=GetImageProfile(next,"icm");
934
333k
    profile=GetImageProfile(next,"iptc");
935
333k
    if (profile == (const StringInfo *) NULL)
936
332k
      profile=GetImageProfile(next,"8bim");
937
333k
    if (IsSourceDataEpochSet() == MagickFalse)
938
333k
      {
939
333k
        char
940
333k
          timestamp[MagickTimeExtent];
941
942
333k
        (void) FormatMagickTime(next->timestamp,sizeof(timestamp),timestamp);
943
333k
        (void) SetImageProperty(next,"date:timestamp",timestamp,exception);
944
333k
        (void) FormatMagickTime((time_t) GetBlobProperties(next)->st_mtime,
945
333k
          sizeof(timestamp),timestamp);
946
333k
        (void) SetImageProperty(next,"date:modify",timestamp,exception);
947
333k
        (void) FormatMagickTime((time_t) GetBlobProperties(next)->st_ctime,
948
333k
          sizeof(timestamp),timestamp);
949
333k
        (void) SetImageProperty(next,"date:create",timestamp,exception);
950
333k
      }
951
333k
    if (constitute_info.delay_flags != NoValue)
952
0
      {
953
0
        if ((constitute_info.delay_flags & GreaterValue) != 0)
954
0
          {
955
0
            if (next->delay > constitute_info.delay)
956
0
              next->delay=constitute_info.delay;
957
0
          }
958
0
        else
959
0
          if ((constitute_info.delay_flags & LessValue) != 0)
960
0
            {
961
0
              if (next->delay < constitute_info.delay)
962
0
                next->delay=constitute_info.delay;
963
0
            }
964
0
          else
965
0
            next->delay=constitute_info.delay;
966
0
        if ((constitute_info.delay_flags & SigmaValue) != 0)
967
0
          next->ticks_per_second=constitute_info.ticks_per_second;
968
0
      }
969
333k
    if (constitute_info.dispose != (const char *) NULL)
970
0
      {
971
0
        ssize_t
972
0
          option_type;
973
974
0
        option_type=ParseCommandOption(MagickDisposeOptions,MagickFalse,
975
0
          constitute_info.dispose);
976
0
        if (option_type >= 0)
977
0
          next->dispose=(DisposeType) option_type;
978
0
      }
979
333k
    if (read_info->verbose != MagickFalse)
980
0
      (void) IdentifyImage(next,stderr,MagickFalse,exception);
981
333k
    image=next;
982
333k
  }
983
289k
  read_info=DestroyImageInfo(read_info);
984
289k
  if (GetBlobError(image) != MagickFalse)
985
289k
    ThrowReaderException(CorruptImageError,"UnableToReadImageData");
986
289k
  return(GetFirstImageInList(image));
987
289k
}
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
0
{
1019
0
  char
1020
0
    read_filename[MagickPathExtent];
1021
1022
0
  Image
1023
0
    *image,
1024
0
    *images;
1025
1026
0
  ImageInfo
1027
0
    *read_info;
1028
1029
  /*
1030
    Read image list from a file.
1031
  */
1032
0
  assert(image_info != (ImageInfo *) NULL);
1033
0
  assert(image_info->signature == MagickCoreSignature);
1034
0
  assert(exception != (ExceptionInfo *) NULL);
1035
0
  if (IsEventLogging() != MagickFalse)
1036
0
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1037
0
      image_info->filename);
1038
0
  read_info=CloneImageInfo(image_info);
1039
0
  *read_info->magick='\0';
1040
0
  (void) SetImageOption(read_info,"filename",filename);
1041
0
  (void) CopyMagickString(read_info->filename,filename,MagickPathExtent);
1042
0
  (void) InterpretImageFilename(read_info,(Image *) NULL,filename,
1043
0
    (int) read_info->scene,read_filename,exception);
1044
0
  if (LocaleCompare(read_filename,read_info->filename) != 0)
1045
0
    {
1046
0
      ExceptionInfo
1047
0
        *sans;
1048
1049
0
      ssize_t
1050
0
        extent,
1051
0
        scene;
1052
1053
      /*
1054
        Images of the form image-%d.png[1-5].
1055
      */
1056
0
      sans=AcquireExceptionInfo();
1057
0
      (void) SetImageInfo(read_info,0,sans);
1058
0
      sans=DestroyExceptionInfo(sans);
1059
0
      if (read_info->number_scenes != 0)
1060
0
        {
1061
0
          (void) CopyMagickString(read_filename,read_info->filename,
1062
0
            MagickPathExtent);
1063
0
          images=NewImageList();
1064
0
          extent=(ssize_t) (read_info->scene+read_info->number_scenes);
1065
0
          scene=(ssize_t) read_info->scene;
1066
0
          for ( ; scene < (ssize_t) extent; scene++)
1067
0
          {
1068
0
            (void) InterpretImageFilename(image_info,(Image *) NULL,
1069
0
              read_filename,(int) scene,read_info->filename,exception);
1070
0
            image=ReadImage(read_info,exception);
1071
0
            if (image == (Image *) NULL)
1072
0
              continue;
1073
0
            AppendImageToList(&images,image);
1074
0
          }
1075
0
          read_info=DestroyImageInfo(read_info);
1076
0
          return(images);
1077
0
        }
1078
0
    }
1079
0
  (void) CopyMagickString(read_info->filename,filename,MagickPathExtent);
1080
0
  image=ReadImage(read_info,exception);
1081
0
  read_info=DestroyImageInfo(read_info);
1082
0
  return(image);
1083
0
}
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
1116
static MagickBooleanType GetImplicitDataImageType(const char *data_url,
1117
  char *magick,ExceptionInfo *exception)
1118
79.1k
{
1119
79.1k
  char
1120
79.1k
    *plus;
1121
1122
79.1k
  const char
1123
79.1k
    *p,
1124
79.1k
    *type,
1125
79.1k
    *slash;
1126
1127
79.1k
  const MagickInfo
1128
79.1k
    *magick_info;
1129
1130
79.1k
  size_t
1131
79.1k
    offset;
1132
1133
79.1k
  if (data_url == (const char *) NULL)
1134
0
    return(MagickFalse);
1135
79.1k
  if (strncmp(data_url,"data:",5) != 0)
1136
25.3k
    return(MagickFalse);
1137
53.7k
  type=data_url+5;
1138
53.7k
  p=type;
1139
4.56M
  while ((*p != '\0') && (*p != ';') && (*p != ','))
1140
4.50M
    p++;
1141
53.7k
  if (p == type)
1142
0
    return(MagickFalse);
1143
53.7k
  slash=(const char *) memchr(type,'/',(size_t) (p-type));
1144
53.7k
  if ((slash == (const char *) NULL) || ((slash+1) >= p))
1145
51.6k
    return(MagickFalse);
1146
2.17k
  offset=(size_t) (p-(slash+1));
1147
2.17k
  if (offset >= MagickPathExtent)
1148
6
    return(MagickFalse);
1149
2.16k
  (void) memcpy(magick,slash+1,offset);
1150
2.16k
  magick[offset]='\0';
1151
2.16k
  plus=strchr(magick,'+');
1152
2.16k
  if (plus != (char *) NULL)
1153
1.90k
    *plus='\0';
1154
2.16k
  if (LocaleNCompare(magick,"x-",2) == 0)
1155
0
    (void) memmove(magick,magick+2,strlen(magick+2)+1);
1156
2.16k
  magick_info=GetMagickInfo(magick,exception);
1157
2.16k
  if ((magick_info == (const MagickInfo *) NULL) ||
1158
0
      (magick_info->format_type == ImplicitFormatType))
1159
2.16k
    return(MagickFalse);
1160
0
  return(MagickTrue);
1161
2.16k
}
1162
1163
MagickExport Image *ReadInlineImage(const ImageInfo *image_info,
1164
  const char *content,ExceptionInfo *exception)
1165
84.7k
{
1166
84.7k
  const char
1167
84.7k
    *p;
1168
1169
84.7k
  Image
1170
84.7k
    *image = (Image *) NULL;
1171
1172
84.7k
  ImageInfo
1173
84.7k
    *read_info;
1174
1175
84.7k
  size_t
1176
84.7k
    length;
1177
1178
84.7k
  unsigned char
1179
84.7k
    *blob;
1180
1181
  /*
1182
    Skip over header (e.g. data:image/gif;base64,).
1183
  */
1184
84.7k
  image=NewImageList();
1185
6.06M
  for (p=content; (*p != ',') && (*p != '\0'); p++) ;
1186
84.7k
  if (*p == '\0')
1187
83.7k
    ThrowReaderException(CorruptImageError,"CorruptImage");
1188
83.7k
  blob=Base64Decode(++p,&length);
1189
83.7k
  if (length == 0)
1190
4.61k
    {
1191
4.61k
      blob=(unsigned char *) RelinquishMagickMemory(blob);
1192
4.61k
      ThrowReaderException(CorruptImageError,"CorruptImage");
1193
0
    }
1194
79.1k
  read_info=CloneImageInfo(image_info);
1195
79.1k
  (void) SetImageInfoProgressMonitor(read_info,(MagickProgressMonitor) NULL,
1196
79.1k
    (void *) NULL);
1197
79.1k
  *read_info->filename='\0';
1198
79.1k
  if (GetImplicitDataImageType(content,read_info->magick,exception) == MagickFalse)
1199
79.1k
    {
1200
79.1k
      blob=(unsigned char *) RelinquishMagickMemory(blob);
1201
79.1k
      read_info=DestroyImageInfo(read_info);
1202
79.1k
      ThrowReaderException(ImageError,"ImageTypeNotSupported");
1203
0
    }
1204
0
  image=BlobToImage(read_info,blob,length,exception);
1205
0
  blob=(unsigned char *) RelinquishMagickMemory(blob);
1206
0
  read_info=DestroyImageInfo(read_info);
1207
0
  return(image);
1208
79.1k
}
1209

1210
/*
1211
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1212
%                                                                             %
1213
%                                                                             %
1214
%                                                                             %
1215
%   W r i t e I m a g e                                                       %
1216
%                                                                             %
1217
%                                                                             %
1218
%                                                                             %
1219
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1220
%
1221
%  WriteImage() writes an image or an image sequence to a file or file handle.
1222
%  If writing to a file is on disk, the name is defined by the filename member
1223
%  of the image structure.  WriteImage() returns MagickFalse is there is a
1224
%  memory shortage or if the image cannot be written.  Check the exception
1225
%  member of image to determine the cause for any failure.
1226
%
1227
%  The format of the WriteImage method is:
1228
%
1229
%      MagickBooleanType WriteImage(const ImageInfo *image_info,Image *image,
1230
%        ExceptionInfo *exception)
1231
%
1232
%  A description of each parameter follows:
1233
%
1234
%    o image_info: the image info.
1235
%
1236
%    o image: the image.
1237
%
1238
%    o exception: return any errors or warnings in this structure.
1239
%
1240
*/
1241
MagickExport MagickBooleanType WriteImage(const ImageInfo *image_info,
1242
  Image *image,ExceptionInfo *exception)
1243
61.5k
{
1244
61.5k
  char
1245
61.5k
    filename[MagickPathExtent];
1246
1247
61.5k
  const char
1248
61.5k
    *option;
1249
1250
61.5k
  const DelegateInfo
1251
61.5k
    *delegate_info;
1252
1253
61.5k
  const MagickInfo
1254
61.5k
    *magick_info;
1255
1256
61.5k
  EncodeImageHandler
1257
61.5k
    *encoder;
1258
1259
61.5k
  ExceptionInfo
1260
61.5k
    *sans_exception;
1261
1262
61.5k
  ImageInfo
1263
61.5k
    *write_info;
1264
1265
61.5k
  MagickBooleanType
1266
61.5k
    status,
1267
61.5k
    temporary;
1268
1269
  /*
1270
    Determine image type from filename prefix or suffix (e.g. image.jpg).
1271
  */
1272
61.5k
  assert(image_info != (ImageInfo *) NULL);
1273
61.5k
  assert(image_info->signature == MagickCoreSignature);
1274
61.5k
  assert(image != (Image *) NULL);
1275
61.5k
  if (IsEventLogging() != MagickFalse)
1276
0
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1277
0
      image_info->filename);
1278
61.5k
  assert(image->signature == MagickCoreSignature);
1279
61.5k
  assert(exception != (ExceptionInfo *) NULL);
1280
61.5k
  sans_exception=AcquireExceptionInfo();
1281
61.5k
  write_info=CloneImageInfo(image_info);
1282
61.5k
  (void) CopyMagickString(write_info->filename,image->filename,
1283
61.5k
    MagickPathExtent);
1284
61.5k
  (void) SetImageInfo(write_info,1,sans_exception);
1285
61.5k
  if (*write_info->magick == '\0')
1286
0
    (void) CopyMagickString(write_info->magick,image->magick,MagickPathExtent);
1287
61.5k
  (void) CopyMagickString(filename,image->filename,MagickPathExtent);
1288
61.5k
  (void) CopyMagickString(image->filename,write_info->filename,
1289
61.5k
    MagickPathExtent);
1290
  /*
1291
    Call appropriate image writer based on image type.
1292
  */
1293
61.5k
  magick_info=GetMagickInfo(write_info->magick,sans_exception);
1294
61.5k
  if (sans_exception->severity == PolicyError)
1295
0
    magick_info=GetMagickInfo(write_info->magick,exception);
1296
61.5k
  sans_exception=DestroyExceptionInfo(sans_exception);
1297
61.5k
  if (magick_info != (const MagickInfo *) NULL)
1298
61.5k
    {
1299
61.5k
      if (GetMagickEndianSupport(magick_info) == MagickFalse)
1300
56.1k
        image->endian=UndefinedEndian;
1301
5.35k
      else
1302
5.35k
        if ((image_info->endian == UndefinedEndian) &&
1303
5.35k
            (GetMagickRawSupport(magick_info) != MagickFalse))
1304
18
          image->endian=GetHostEndian();
1305
61.5k
    }
1306
61.5k
  if ((image->ping != MagickFalse) &&
1307
0
      (SyncImagePixelCache(image,exception) == MagickFalse))
1308
0
    {
1309
0
      write_info=DestroyImageInfo(write_info);
1310
0
      return(MagickFalse);
1311
0
    }
1312
61.5k
  SyncImageProfiles(image);
1313
61.5k
  DisassociateImageStream(image);
1314
61.5k
  option=GetImageOption(image_info,"delegate:bimodal");
1315
61.5k
  if ((IsStringTrue(option) != MagickFalse) &&
1316
0
      (write_info->page == (char *) NULL) &&
1317
0
      (GetPreviousImageInList(image) == (Image *) NULL) &&
1318
0
      (GetNextImageInList(image) == (Image *) NULL) &&
1319
0
      (IsTaintImage(image) == MagickFalse) )
1320
0
    {
1321
0
      delegate_info=GetDelegateInfo(image->magick,write_info->magick,exception);
1322
0
      if ((delegate_info != (const DelegateInfo *) NULL) &&
1323
0
          (GetDelegateMode(delegate_info) == 0) &&
1324
0
          (IsPathAccessible(image->magick_filename) != MagickFalse))
1325
0
        {
1326
          /*
1327
            Process image with bi-modal delegate.
1328
          */
1329
0
          (void) CopyMagickString(image->filename,image->magick_filename,
1330
0
            MagickPathExtent);
1331
0
          status=InvokeDelegate(write_info,image,image->magick,
1332
0
            write_info->magick,exception);
1333
0
          write_info=DestroyImageInfo(write_info);
1334
0
          (void) CopyMagickString(image->filename,filename,MagickPathExtent);
1335
0
          return(status);
1336
0
        }
1337
0
    }
1338
61.5k
  status=MagickFalse;
1339
61.5k
  temporary=MagickFalse;
1340
61.5k
  if ((magick_info != (const MagickInfo *) NULL) &&
1341
61.5k
      (GetMagickEncoderSeekableStream(magick_info) != MagickFalse))
1342
20.0k
    {
1343
20.0k
      char
1344
20.0k
        image_filename[MagickPathExtent];
1345
1346
20.0k
      (void) CopyMagickString(image_filename,image->filename,MagickPathExtent);
1347
20.0k
      status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
1348
20.0k
      (void) CopyMagickString(image->filename, image_filename,MagickPathExtent);
1349
20.0k
      if (status != MagickFalse)
1350
20.0k
        {
1351
20.0k
          if (IsBlobSeekable(image) == MagickFalse)
1352
0
            {
1353
              /*
1354
                A seekable stream is required by the encoder.
1355
              */
1356
0
              write_info->adjoin=MagickTrue;
1357
0
              (void) CopyMagickString(write_info->filename,image->filename,
1358
0
                MagickPathExtent);
1359
0
              (void) AcquireUniqueFilename(image->filename);
1360
0
              temporary=MagickTrue;
1361
0
            }
1362
20.0k
          if (CloseBlob(image) == MagickFalse)
1363
0
            status=MagickFalse;
1364
20.0k
        }
1365
20.0k
    }
1366
61.5k
  encoder=GetImageEncoder(magick_info);
1367
61.5k
  if (encoder != (EncodeImageHandler *) NULL)
1368
61.5k
    {
1369
      /*
1370
        Call appropriate image writer based on image type.
1371
      */
1372
61.5k
      if (GetMagickEncoderThreadSupport(magick_info) == MagickFalse)
1373
0
        LockSemaphoreInfo(magick_info->semaphore);
1374
61.5k
      status=IsCoderAuthorized(magick_info->magick_module,magick_info->name,
1375
61.5k
        WritePolicyRights,exception);
1376
61.5k
      if (status != MagickFalse)
1377
61.5k
        status=encoder(write_info,image,exception);
1378
61.5k
      if (GetMagickEncoderThreadSupport(magick_info) == MagickFalse)
1379
0
        UnlockSemaphoreInfo(magick_info->semaphore);
1380
61.5k
    }
1381
0
  else
1382
0
    {
1383
0
      delegate_info=GetDelegateInfo((char *) NULL,write_info->magick,exception);
1384
0
      if (delegate_info != (DelegateInfo *) NULL)
1385
0
        {
1386
          /*
1387
            Process the image with delegate.
1388
          */
1389
0
          *write_info->filename='\0';
1390
0
          if (GetDelegateThreadSupport(delegate_info) == MagickFalse)
1391
0
            LockSemaphoreInfo(delegate_info->semaphore);
1392
0
          status=InvokeDelegate(write_info,image,(char *) NULL,
1393
0
            write_info->magick,exception);
1394
0
          if (GetDelegateThreadSupport(delegate_info) == MagickFalse)
1395
0
            UnlockSemaphoreInfo(delegate_info->semaphore);
1396
0
          (void) CopyMagickString(image->filename,filename,MagickPathExtent);
1397
0
        }
1398
0
      else
1399
0
        {
1400
0
          sans_exception=AcquireExceptionInfo();
1401
0
          magick_info=GetMagickInfo(write_info->magick,sans_exception);
1402
0
          if (sans_exception->severity == PolicyError)
1403
0
            magick_info=GetMagickInfo(write_info->magick,exception);
1404
0
          sans_exception=DestroyExceptionInfo(sans_exception);
1405
0
          if ((write_info->affirm == MagickFalse) &&
1406
0
              (magick_info == (const MagickInfo *) NULL))
1407
0
            {
1408
0
              (void) CopyMagickString(write_info->magick,image->magick,
1409
0
                MagickPathExtent);
1410
0
              magick_info=GetMagickInfo(write_info->magick,exception);
1411
0
            }
1412
0
          encoder=GetImageEncoder(magick_info);
1413
0
          if (encoder == (EncodeImageHandler *) NULL)
1414
0
            {
1415
0
              char
1416
0
                extension[MagickPathExtent];
1417
1418
0
              GetPathComponent(image->filename,ExtensionPath,extension);
1419
0
              if (*extension != '\0')
1420
0
                magick_info=GetMagickInfo(extension,exception);
1421
0
              else
1422
0
                magick_info=GetMagickInfo(image->magick,exception);
1423
0
              (void) CopyMagickString(image->filename,filename,
1424
0
                MagickPathExtent);
1425
0
              encoder=GetImageEncoder(magick_info);
1426
0
              (void) ThrowMagickException(exception,GetMagickModule(),
1427
0
                MissingDelegateWarning,"NoEncodeDelegateForThisImageFormat",
1428
0
                "`%s'",write_info->magick);
1429
0
            }
1430
0
          if (encoder == (EncodeImageHandler *) NULL)
1431
0
            {
1432
0
              magick_info=GetMagickInfo(image->magick,exception);
1433
0
              encoder=GetImageEncoder(magick_info);
1434
0
              if (encoder == (EncodeImageHandler *) NULL)
1435
0
                (void) ThrowMagickException(exception,GetMagickModule(),
1436
0
                  MissingDelegateError,"NoEncodeDelegateForThisImageFormat",
1437
0
                  "`%s'",write_info->magick);
1438
0
            }
1439
0
          if (encoder != (EncodeImageHandler *) NULL)
1440
0
            {
1441
              /*
1442
                Call appropriate image writer based on image type.
1443
              */
1444
0
              if (GetMagickEncoderThreadSupport(magick_info) == MagickFalse)
1445
0
                LockSemaphoreInfo(magick_info->semaphore);
1446
0
              status=IsCoderAuthorized(magick_info->magick_module,magick_info->name,
1447
0
                WritePolicyRights,exception);
1448
0
              if (status != MagickFalse)
1449
0
                status=encoder(write_info,image,exception);
1450
0
              if (GetMagickEncoderThreadSupport(magick_info) == MagickFalse)
1451
0
                UnlockSemaphoreInfo(magick_info->semaphore);
1452
0
            }
1453
0
        }
1454
0
    }
1455
61.5k
  if (temporary != MagickFalse)
1456
0
    {
1457
      /*
1458
        Copy temporary image file to permanent.
1459
      */
1460
0
      status=OpenBlob(write_info,image,ReadBinaryBlobMode,exception);
1461
0
      if (status != MagickFalse)
1462
0
        {
1463
0
          (void) RelinquishUniqueFileResource(write_info->filename);
1464
0
          status=ImageToFile(image,write_info->filename,exception);
1465
0
        }
1466
0
      if (CloseBlob(image) == MagickFalse)
1467
0
        status=MagickFalse;
1468
0
      (void) RelinquishUniqueFileResource(image->filename);
1469
0
      (void) CopyMagickString(image->filename,write_info->filename,
1470
0
        MagickPathExtent);
1471
0
    }
1472
61.5k
  if ((LocaleCompare(write_info->magick,"info") != 0) &&
1473
61.5k
      (write_info->verbose != MagickFalse))
1474
0
    (void) IdentifyImage(image,stdout,MagickFalse,exception);
1475
61.5k
  write_info=DestroyImageInfo(write_info);
1476
61.5k
  if (GetBlobError(image) != MagickFalse)
1477
61.5k
    ThrowWriterException(FileOpenError,"UnableToWriteFile");
1478
61.5k
  return(status);
1479
61.5k
}
1480

1481
/*
1482
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1483
%                                                                             %
1484
%                                                                             %
1485
%                                                                             %
1486
%   W r i t e I m a g e s                                                     %
1487
%                                                                             %
1488
%                                                                             %
1489
%                                                                             %
1490
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1491
%
1492
%  WriteImages() writes an image sequence into one or more files.  While
1493
%  WriteImage() can write an image sequence, it is limited to writing
1494
%  the sequence into a single file using a format which supports multiple
1495
%  frames.   WriteImages(), however, does not have this limitation, instead it
1496
%  generates multiple output files if necessary (or when requested).  When
1497
%  ImageInfo's adjoin flag is set to MagickFalse, the file name is expected
1498
%  to include a printf-style formatting string for the frame number (e.g.
1499
%  "image%02d.png").
1500
%
1501
%  The format of the WriteImages method is:
1502
%
1503
%      MagickBooleanType WriteImages(const ImageInfo *image_info,Image *images,
1504
%        const char *filename,ExceptionInfo *exception)
1505
%
1506
%  A description of each parameter follows:
1507
%
1508
%    o image_info: the image info.
1509
%
1510
%    o images: the image list.
1511
%
1512
%    o filename: the image filename.
1513
%
1514
%    o exception: return any errors or warnings in this structure.
1515
%
1516
*/
1517
MagickExport MagickBooleanType WriteImages(const ImageInfo *image_info,
1518
  Image *images,const char *filename,ExceptionInfo *exception)
1519
32.8k
{
1520
32.8k
#define WriteImageTag  "Write/Image"
1521
1522
32.8k
  ExceptionInfo
1523
32.8k
    *sans_exception;
1524
1525
32.8k
  ImageInfo
1526
32.8k
    *write_info;
1527
1528
32.8k
  MagickBooleanType
1529
32.8k
    proceed;
1530
1531
32.8k
  MagickOffsetType
1532
32.8k
    progress;
1533
1534
32.8k
  MagickProgressMonitor
1535
32.8k
    progress_monitor;
1536
1537
32.8k
  MagickSizeType
1538
32.8k
    number_images;
1539
1540
32.8k
  MagickStatusType
1541
32.8k
    status;
1542
1543
32.8k
  Image
1544
32.8k
    *p;
1545
1546
32.8k
  assert(image_info != (const ImageInfo *) NULL);
1547
32.8k
  assert(image_info->signature == MagickCoreSignature);
1548
32.8k
  assert(images != (Image *) NULL);
1549
32.8k
  assert(images->signature == MagickCoreSignature);
1550
32.8k
  if (IsEventLogging() != MagickFalse)
1551
0
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
1552
32.8k
  assert(exception != (ExceptionInfo *) NULL);
1553
32.8k
  write_info=CloneImageInfo(image_info);
1554
32.8k
  *write_info->magick='\0';
1555
32.8k
  images=GetFirstImageInList(images);
1556
32.8k
  if (images == (Image *) NULL)
1557
0
    return(MagickFalse);
1558
32.8k
  if (filename != (const char *) NULL)
1559
65.6k
    for (p=images; p != (Image *) NULL; p=GetNextImageInList(p))
1560
32.8k
      (void) CopyMagickString(p->filename,filename,MagickPathExtent);
1561
32.8k
  (void) CopyMagickString(write_info->filename,images->filename,
1562
32.8k
    MagickPathExtent);
1563
32.8k
  sans_exception=AcquireExceptionInfo();
1564
32.8k
  (void) SetImageInfo(write_info,(unsigned int) GetImageListLength(images),
1565
32.8k
    sans_exception);
1566
32.8k
  sans_exception=DestroyExceptionInfo(sans_exception);
1567
32.8k
  if (*write_info->magick == '\0')
1568
31.9k
    (void) CopyMagickString(write_info->magick,images->magick,MagickPathExtent);
1569
32.8k
  p=images;
1570
32.8k
  for ( ; GetNextImageInList(p) != (Image *) NULL; p=GetNextImageInList(p))
1571
0
  {
1572
0
    if (p->scene >= GetNextImageInList(p)->scene)
1573
0
      {
1574
0
        ssize_t
1575
0
          i;
1576
1577
        /*
1578
          Generate consistent scene numbers.
1579
        */
1580
0
        i=(ssize_t) images->scene;
1581
0
        for (p=images; p != (Image *) NULL; p=GetNextImageInList(p))
1582
0
          p->scene=(size_t) i++;
1583
0
        break;
1584
0
      }
1585
0
  }
1586
  /*
1587
    Write images.
1588
  */
1589
32.8k
  status=MagickTrue;
1590
32.8k
  progress_monitor=(MagickProgressMonitor) NULL;
1591
32.8k
  progress=0;
1592
32.8k
  number_images=GetImageListLength(images);
1593
32.8k
  for (p=images; p != (Image *) NULL; p=GetNextImageInList(p))
1594
32.8k
  {
1595
32.8k
    if (number_images != 1)
1596
0
      progress_monitor=SetImageProgressMonitor(p,(MagickProgressMonitor) NULL,
1597
0
        p->client_data);
1598
32.8k
    status&=(MagickStatusType) WriteImage(write_info,p,exception);
1599
32.8k
    if (write_info->blob != (void *) NULL)
1600
31.9k
      SyncBlobStream(write_info,p,images);
1601
32.8k
    if (number_images != 1)
1602
0
      (void) SetImageProgressMonitor(p,progress_monitor,p->client_data);
1603
32.8k
    if (write_info->adjoin != MagickFalse)
1604
32.8k
      break;
1605
0
    if (number_images != 1)
1606
0
      {
1607
#if defined(MAGICKCORE_OPENMP_SUPPORT)
1608
        #pragma omp atomic
1609
#endif
1610
0
        progress++;
1611
0
        proceed=SetImageProgress(p,WriteImageTag,progress,number_images);
1612
0
        if (proceed == MagickFalse)
1613
0
          break;
1614
0
      }
1615
0
  }
1616
32.8k
  write_info=DestroyImageInfo(write_info);
1617
32.8k
  return(status != 0 ? MagickTrue : MagickFalse);
1618
32.8k
}