Coverage Report

Created: 2026-10-28 07:26

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/graphicsmagick/magick/constitute.c
Line
Count
Source
1
/*
2
% Copyright (C) 2003 - 2022 GraphicsMagick Group
3
% Copyright (C) 2002 ImageMagick Studio
4
% SPDX-License-Identifier: MIT
5
%
6
% This program is covered by multiple licenses, which are described in
7
% Copyright.txt. You should have received a copy of Copyright.txt with this
8
% package; otherwise see http://www.graphicsmagick.org/www/Copyright.html.
9
%
10
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
11
%                                                                             %
12
%                                                                             %
13
%                                                                             %
14
%     CCCC   OOO   N   N  SSSSS  TTTTT  IIIII  TTTTT  U   U  TTTTT  EEEEE     %
15
%    C      O   O  NN  N  SS       T      I      T    U   U    T    E         %
16
%    C      O   O  N N N  ESSS     T      I      T    U   U    T    EEE       %
17
%    C      O   O  N  NN     SS    T      I      T    U   U    T    E         %
18
%     CCCC   OOO   N   N  SSSSS    T    IIIII    T     UUU     T    EEEEE     %
19
%                                                                             %
20
%                                                                             %
21
%                      Methods to Constitute an Image                         %
22
%                                                                             %
23
%                                                                             %
24
%                             Software Design                                 %
25
%                               John Cristy                                   %
26
%                               October 1998                                  %
27
%                                                                             %
28
%                           Re-implemented By                                 %
29
%                            Bob Friesenhahn                                  %
30
%                               2003-2008                                     %
31
%                                                                             %
32
%                         Small Float Support By                              %
33
%                             Richard Nolde                                   %
34
%                             December, 2008                                  %
35
%                                                                             %
36
%                                                                             %
37
%                                                                             %
38
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
39
%
40
%
41
*/
42

43
/*
44
  Include declarations.
45
*/
46
#include "magick/studio.h"
47
#include "magick/analyze.h"
48
#include "magick/attribute.h"
49
#include "magick/blob.h"
50
#include "magick/colormap.h"
51
#include "magick/constitute.h"
52
#include "magick/delegate.h"
53
#include "magick/describe.h"
54
#include "magick/enum_strings.h"
55
#include "magick/log.h"
56
#include "magick/magick.h"
57
#include "magick/monitor.h"
58
#include "magick/pixel_cache.h"
59
#include "magick/semaphore.h"
60
#include "magick/tempfile.h"
61
#include "magick/utility.h"
62

63
/*
64
  Type definitions
65
*/
66
typedef enum
67
{
68
  BlueMapQuanum,
69
  GreenMapQuantum,
70
  IntensityMapQuantum,
71
  TransparencyMapQuantum,
72
  PadMapQuantum,
73
  RedMapQuantum,
74
  OpacityMapQuantum
75
} MapQuantumType;
76
77
typedef enum {
78
  UndefinedDispatchType,
79
  BGRDispatchType,
80
  BGRADispatchType,
81
  BGRPDispatchType,
82
  RGBDispatchType,
83
  RGBADispatchType,
84
  IDispatchType
85
} DispatchType;
86

87
static SemaphoreInfo
88
  *constitute_semaphore = (SemaphoreInfo *) NULL;
89

90
/*
91
  Forward declarations.
92
*/
93
static Image
94
  *ReadImages(const ImageInfo *,ExceptionInfo *);
95
96

97
/*
98
  Macros
99
*/
100

101
/*
102
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
103
%                                                                             %
104
%                                                                             %
105
%                                                                             %
106
%   C o n s t i t u t e I m a g e                                             %
107
%                                                                             %
108
%                                                                             %
109
%                                                                             %
110
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
111
%
112
%  ConstituteImage() returns an Image corresponding to an image stored
113
%  in a raw memory array format. The pixel data must be in scanline order
114
%  top-to-bottom. The data can be unsigned char, unsigned short int, unsigned
115
%  int, unsigned long, float, or double.  Float and double require the pixels
116
%  to be normalized to the range [0..1], otherwise the range is [0..MaxVal]
117
%  where MaxVal is the maximum possible value for that type.
118
%
119
%  Note that for most 32-bit architectures the size of an unsigned long is
120
%  the same as unsigned int, but for 64-bit architectures observing the LP64
121
%  standard, an unsigned long is 64 bits, while an unsigned int remains 32
122
%  bits. This should be considered when deciding if the data should be
123
%  described as "Integer" or "Long".
124
%
125
%  For example, to create a 640x480 image from unsigned red-green-blue
126
%  character data, use
127
%
128
%      image=ConstituteImage(640,480,"RGB",CharPixel,pixels,&exception);
129
%
130
%  The format of the Constitute method is:
131
%
132
%      Image *ConstituteImage(const unsigned long width,
133
%        const unsigned long height,const char *map,const StorageType type,
134
%        const void *pixels,ExceptionInfo *exception)
135
%
136
%  A description of each parameter follows:
137
%
138
%    o width: width in pixels of the image.
139
%
140
%    o height: height in pixels of the image.
141
%
142
%    o map: This string reflects the expected ordering of the pixel array.
143
%      It can be any combination or order of R = red, G = green, B = blue,
144
%      A = alpha (same as Transparency), O = Opacity, T = Transparency,
145
%      C = cyan, Y = yellow, M = magenta, K = black, or I = intensity
146
%      (for grayscale). Specify "P" = pad, to skip over a quantum which is
147
%      intentionally ignored. Creation of an alpha channel for CMYK images
148
%      is currently not supported.
149
%
150
%    o type: Define the data type of the pixels.  Float and double types are
151
%      expected to be normalized [0..1] otherwise [0..MaxRGB].  Choose from
152
%      these types: CharPixel, ShortPixel, IntegerPixel, LongPixel, FloatPixel,
153
%      or DoublePixel.
154
%
155
%    o pixels: This array of values contain the pixel components as defined by
156
%      map and type.  You must preallocate this array where the expected
157
%      length varies depending on the values of width, height, map, and type.
158
%
159
%    o exception: Return any errors or warnings in this structure.
160
%
161
%
162
*/
163
164
MagickExport Image *ConstituteImage(const unsigned long width,
165
  const unsigned long height,const char *map,const StorageType type,
166
  const void *pixels,ExceptionInfo *exception)
167
0
{
168
0
  Image
169
0
    *image;
170
171
0
  long
172
0
    y;
173
174
0
  PixelPacket
175
0
    * restrict q;
176
177
0
  register Quantum
178
0
    quantum;
179
180
0
  MapQuantumType
181
0
    switch_map[MaxTextExtent/sizeof(MapQuantumType)];
182
183
0
  register IndexPacket
184
0
    * restrict indexes;
185
186
0
  register long
187
0
    i,
188
0
    x;
189
190
0
  size_t
191
0
    length;
192
193
0
  unsigned int
194
0
    storage_type_depth = QuantumDepth;
195
196
  /*
197
    Allocate image structure.
198
  */
199
0
  assert(pixels != (void *) NULL);
200
0
  assert(exception != (ExceptionInfo *) NULL);
201
0
  assert(exception->signature == MagickSignature);
202
  /* SetExceptionInfo(exception,UndefinedException); */
203
0
  image=AllocateImage((ImageInfo *) NULL);
204
0
  if (image == (Image *) NULL)
205
0
    return((Image *) NULL);
206
0
  if ((width == 0) || (height == 0))
207
0
    ThrowBinaryException3(OptionError,UnableToConstituteImage,
208
0
      NonzeroWidthAndHeightRequired);
209
0
  image->columns=width;
210
0
  image->rows=height;
211
212
0
  switch (type)
213
0
    {
214
0
    case CharPixel : storage_type_depth = sizeof(unsigned char)*8 ; break;
215
0
    case ShortPixel : storage_type_depth = sizeof(unsigned short)*8 ; break;
216
0
    case IntegerPixel : storage_type_depth = sizeof(unsigned short)*8 ; break;
217
0
    case LongPixel : storage_type_depth = sizeof(unsigned long)*8 ; break;
218
0
    case FloatPixel : storage_type_depth = sizeof(float)*8 ; break;
219
0
    case DoublePixel : storage_type_depth = sizeof(double)*8 ; break;
220
0
    }
221
222
0
  image->depth = Min(storage_type_depth,QuantumDepth);
223
224
  /*
225
    Handle a few common special cases in order to improve performance.
226
  */
227
0
  if (type == CharPixel)
228
0
    {
229
0
      DispatchType
230
0
        dispatch_type=UndefinedDispatchType;
231
232
0
      if (LocaleCompare(map,"BGR") == 0)
233
0
        dispatch_type=BGRDispatchType;
234
0
      else if (LocaleCompare(map,"BGRA") == 0)
235
0
        dispatch_type=BGRADispatchType;
236
0
      else if (LocaleCompare(map,"BGRP") == 0)
237
0
        dispatch_type=BGRPDispatchType;
238
0
      else if (LocaleCompare(map,"RGB") == 0)
239
0
        dispatch_type=RGBDispatchType;
240
0
      else if (LocaleCompare(map,"RGBA") == 0)
241
0
        dispatch_type=RGBADispatchType;
242
0
      else if (LocaleCompare(map,"I") == 0)
243
0
        {
244
0
          if (!AllocateImageColormap(image,MaxColormapSize))
245
0
            ThrowImageException3(ResourceLimitError,MemoryAllocationFailed,
246
0
                                 UnableToConstituteImage);
247
0
          dispatch_type=IDispatchType;
248
0
        }
249
250
0
      if (dispatch_type != UndefinedDispatchType)
251
0
        {
252
0
          register const unsigned char
253
0
            * restrict p = (const unsigned char*) pixels;
254
255
0
          for (y=0; y < (long) image->rows; y++)
256
0
            {
257
0
              q=SetImagePixels(image,0,y,image->columns,1);
258
0
              if (q == (PixelPacket *) NULL)
259
0
                break;
260
0
              indexes=AccessMutableIndexes(image);
261
262
0
              switch (dispatch_type)
263
0
                {
264
0
                case BGRDispatchType:
265
0
                  {
266
0
                    for (x=(long) image->columns; x != 0; x--)
267
0
                      {
268
0
                        SetBlueSample(q,ScaleCharToQuantum(*p++));
269
0
                        SetGreenSample(q,ScaleCharToQuantum(*p++));
270
0
                        SetRedSample(q,ScaleCharToQuantum(*p++));
271
0
                        SetOpacitySample(q,OpaqueOpacity);
272
0
                        q++;
273
0
                      }
274
0
                    break;
275
0
                  }
276
0
                case BGRADispatchType:
277
0
                  {
278
0
                    image->matte=True;
279
0
                    for (x=(long) image->columns; x != 0; x--)
280
0
                      {
281
0
                        SetBlueSample(q,ScaleCharToQuantum(*p++));
282
0
                        SetGreenSample(q,ScaleCharToQuantum(*p++));
283
0
                        SetRedSample(q,ScaleCharToQuantum(*p++));
284
0
                        SetOpacitySample(q,(Quantum) MaxRGB-ScaleCharToQuantum(*p++));
285
0
                        q++;
286
0
                      }
287
0
                    break;
288
0
                  }
289
0
                case BGRPDispatchType:
290
0
                  {
291
0
                    for (x=(long) image->columns; x != 0; x--)
292
0
                      {
293
0
                        SetBlueSample(q,ScaleCharToQuantum(*p++));
294
0
                        SetGreenSample(q,ScaleCharToQuantum(*p++));
295
0
                        SetRedSample(q,ScaleCharToQuantum(*p++));
296
0
                        p++;
297
0
                        SetOpacitySample(q,OpaqueOpacity);
298
0
                        q++;
299
0
                      }
300
0
                    break;
301
0
                  }
302
0
                case RGBDispatchType:
303
0
                  {
304
0
                    for (x=(long) image->columns; x != 0; x--)
305
0
                      {
306
0
                        SetRedSample(q,ScaleCharToQuantum(*p++));
307
0
                        SetGreenSample(q,ScaleCharToQuantum(*p++));
308
0
                        SetBlueSample(q,ScaleCharToQuantum(*p++));
309
0
                        SetOpacitySample(q,OpaqueOpacity);
310
0
                        q++;
311
0
                      }
312
0
                    break;
313
0
                  }
314
0
                case RGBADispatchType:
315
0
                  {
316
0
                    image->matte=True;
317
0
                    for (x=(long) image->columns; x != 0; x--)
318
0
                      {
319
0
                        SetRedSample(q,ScaleCharToQuantum(*p++));
320
0
                        SetGreenSample(q,ScaleCharToQuantum(*p++));
321
0
                        SetBlueSample(q,ScaleCharToQuantum(*p++));
322
0
                        SetOpacitySample(q,MaxRGB-ScaleCharToQuantum(*p++));
323
0
                        q++;
324
0
                      }
325
0
                    break;
326
0
                  }
327
0
                case IDispatchType:
328
0
                  {
329
0
                    for (x=(long) image->columns; x != 0; x--)
330
0
                      {
331
0
                        *indexes=ScaleQuantumToIndex(ScaleCharToQuantum(*p++));
332
0
                        SetGraySample(q,image->colormap[*indexes].red);
333
0
                        SetOpacitySample(q,OpaqueOpacity);
334
0
                        indexes++;
335
0
                        q++;
336
0
                      }
337
0
                    break;
338
0
                  }
339
0
#if !defined(__COVERITY__)
340
0
                case UndefinedDispatchType:
341
0
                  {
342
0
                    break;
343
0
                  }
344
#else
345
                default:
346
                  {
347
                    break;
348
                  }
349
#endif
350
0
                } /* end switch */
351
0
              if (!SyncImagePixels(image))
352
0
                break;
353
0
            } /* end for (y=0; y < (long) image->rows; y++) */
354
0
          if (dispatch_type == IDispatchType)
355
0
            {
356
0
              (void) IsMonochromeImage(image,exception);
357
0
              image->is_grayscale=True;
358
0
            }
359
0
          return (image);
360
0
        } /* end if (dispatch_type != UndefinedDispatchType) */
361
0
    } /* end if (type == CharPixel) */
362
363
  /*
364
    Prepare a validated and more efficient version of the map.
365
  */
366
0
  length=strlen(map);
367
0
  length=Min(length,sizeof(switch_map)/sizeof(MapQuantumType));
368
0
  for (i=0; i < (long) length; i++)
369
0
    {
370
0
      switch ((int) toupper((int) map[i]))
371
0
        {
372
0
        case 'R':
373
0
          {
374
0
            switch_map[i]=RedMapQuantum;
375
0
            break;
376
0
          }
377
0
        case 'G':
378
0
          {
379
0
            switch_map[i]=GreenMapQuantum;
380
0
            break;
381
0
          }
382
0
        case 'B':
383
0
          {
384
0
            switch_map[i]=BlueMapQuanum;
385
0
            break;
386
0
          }
387
0
        case 'A':
388
0
          {
389
0
            switch_map[i]=TransparencyMapQuantum;
390
0
            image->matte=True;
391
0
            break;
392
0
          }
393
0
        case 'C':
394
0
          {
395
0
            image->colorspace=CMYKColorspace;
396
0
            switch_map[i]=RedMapQuantum;
397
0
            break;
398
0
          }
399
0
        case 'M':
400
0
          {
401
0
            image->colorspace=CMYKColorspace;
402
0
            switch_map[i]=GreenMapQuantum;
403
0
            break;
404
0
          }
405
0
        case 'Y':
406
0
          {
407
0
            image->colorspace=CMYKColorspace;
408
0
            switch_map[i]=BlueMapQuanum;
409
0
            break;
410
0
          }
411
0
        case 'K':
412
0
          {
413
0
            image->colorspace=CMYKColorspace;
414
0
            switch_map[i]=OpacityMapQuantum;
415
0
            break;
416
0
          }
417
0
        case 'I':
418
0
          {
419
0
            if (!AllocateImageColormap(image,MaxColormapSize))
420
0
              ThrowImageException3(ResourceLimitError,MemoryAllocationFailed,
421
0
                UnableToConstituteImage);
422
0
            switch_map[i]=IntensityMapQuantum;
423
0
            break;
424
0
          }
425
0
        case 'O':
426
0
          {
427
0
            switch_map[i]=OpacityMapQuantum;
428
0
            image->matte=True;
429
0
            break;
430
0
          }
431
0
        case 'P':
432
0
          {
433
0
            switch_map[i]=PadMapQuantum;
434
0
            break;
435
0
          }
436
0
        case 'T':
437
0
          {
438
0
            switch_map[i]=TransparencyMapQuantum;
439
0
            image->matte=True;
440
0
            break;
441
0
          }
442
0
        default:
443
0
          {
444
0
            DestroyImage(image);
445
0
            ThrowImageException(OptionError,UnrecognizedPixelMap,map)
446
0
          }
447
0
        }
448
0
    }
449
450
  /*
451
    Transfer the pixels from the pixel data array to the image.
452
  */
453
0
  for (y=0; y < (long) image->rows; y++)
454
0
    {
455
0
      q=SetImagePixels(image,0,y,image->columns,1);
456
0
      if (q == (PixelPacket *) NULL)
457
0
        break;
458
0
      indexes=AccessMutableIndexes(image);
459
0
      for (x=0; x < (long) image->columns; x++)
460
0
        {
461
0
          SetRedSample(q,0);
462
0
          SetGreenSample(q,0);
463
0
          SetBlueSample(q,0);
464
0
          if (image->colorspace == CMYKColorspace)
465
0
            {
466
0
              SetBlackSample(q,0);
467
0
              *indexes=OpaqueOpacity;
468
0
            }
469
0
          else
470
0
            {
471
0
              SetOpacitySample(q,OpaqueOpacity);
472
0
            }
473
0
          for (i=0; i < (long) length; i++)
474
0
            {
475
              /*
476
                Input a quantum
477
              */
478
0
              quantum=0U;
479
480
0
              switch (type)
481
0
                {
482
0
                case CharPixel:
483
0
                  {
484
0
                    register const unsigned char *p = (const unsigned char*) pixels;
485
0
                    quantum=ScaleCharToQuantum(*p++);
486
0
                    pixels = (const void *) p;
487
0
                    break;
488
0
                  }
489
0
                case ShortPixel:
490
0
                  {
491
0
                    register const unsigned short *p = (const unsigned short*) pixels;
492
0
                    quantum=ScaleShortToQuantum(*p++);
493
0
                    pixels = (const void *) p;
494
0
                    break;
495
0
                  }
496
0
                case IntegerPixel:
497
0
                  {
498
0
                    register const unsigned int *p = (const unsigned int*) pixels;
499
0
                    quantum=ScaleLongToQuantum(*p++);
500
0
                    pixels = (const void *) p;
501
0
                    break;
502
0
                  }
503
0
                case LongPixel:
504
0
                  {
505
0
                    register const unsigned long *p = (const unsigned long*) pixels;
506
0
                    quantum=ScaleLongToQuantum(*p++);
507
0
                    pixels = (const void *) p;
508
0
                    break;
509
0
                  }
510
0
                case FloatPixel:
511
0
                  {
512
0
                    double quantum_float;
513
0
                    register const float *p = (const float*) pixels;
514
0
                    quantum_float=(double) MaxRGB*(*p++);
515
0
                    quantum=RoundDoubleToQuantum(quantum_float);
516
0
                    pixels = (const void *) p;
517
0
                    break;
518
0
                  }
519
0
                case DoublePixel:
520
0
                  {
521
0
                    double quantum_float;
522
0
                    register const double *p = (const double*) pixels;
523
0
                    quantum_float=(double) MaxRGB*(*p++);
524
0
                    quantum=RoundDoubleToQuantum(quantum_float);
525
0
                    pixels = (const void *) p;
526
0
                    break;
527
0
                  }
528
0
                }
529
530
              /*
531
                Transfer quantum to image
532
              */
533
0
              switch (switch_map[i])
534
0
                {
535
0
                case RedMapQuantum:
536
0
                  {
537
0
                    SetRedSample(q,quantum);
538
0
                    break;
539
0
                  }
540
0
                case GreenMapQuantum:
541
0
                  {
542
0
                    SetGreenSample(q,quantum);
543
0
                    break;
544
0
                  }
545
0
                case BlueMapQuanum:
546
0
                  {
547
0
                    SetBlueSample(q,quantum);
548
0
                    break;
549
0
                  }
550
0
                case OpacityMapQuantum:
551
0
                  {
552
0
                    SetOpacitySample(q,quantum);
553
0
                    break;
554
0
                  }
555
0
                case TransparencyMapQuantum:
556
0
                  {
557
0
                    SetOpacitySample(q,MaxRGB-quantum);
558
0
                    break;
559
0
                  }
560
0
                case IntensityMapQuantum:
561
0
                  {
562
0
                    *indexes=ScaleQuantumToIndex(quantum);
563
0
                    SetGraySample(q,image->colormap[*indexes].red);
564
0
                    break;
565
0
                  }
566
0
                case PadMapQuantum:
567
0
                  {
568
                    /* Discard quantum */
569
0
                    break;
570
0
                  }
571
0
                }
572
0
            }
573
0
          if (NULL != (IndexPacket *) indexes)
574
0
            indexes++;
575
0
          q++;
576
0
        }
577
0
      if (!SyncImagePixels(image))
578
0
        break;
579
0
    }
580
581
0
  if (image->storage_class == PseudoClass)
582
0
    {
583
      /*
584
        Check and cache monochrome and grayscale status
585
      */
586
0
      (void) IsMonochromeImage(image,exception);
587
0
      if (image->is_monochrome)
588
0
        image->is_grayscale=True;
589
0
      else
590
0
        (void) IsGrayImage(image,exception);
591
0
    }
592
0
  return(image);
593
0
}
594

595
/*
596
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
597
%                                                                             %
598
%                                                                             %
599
%                                                                             %
600
+   D e s t r o y C o n s t i t u t e                                         %
601
%                                                                             %
602
%                                                                             %
603
%                                                                             %
604
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
605
%
606
%  DestroyConstitute() destroys the constitute environment.
607
%
608
%  The format of the DestroyConstitute method is:
609
%
610
%      DestroyConstitute(void)
611
%
612
%
613
*/
614
MagickExport void DestroyConstitute(void)
615
0
{
616
0
  DestroySemaphoreInfo(&constitute_semaphore);
617
0
}
618

619
/*
620
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
621
%                                                                             %
622
%                                                                             %
623
%                                                                             %
624
%   D i s p a t c h I m a g e                                                 %
625
%                                                                             %
626
%                                                                             %
627
%                                                                             %
628
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
629
%
630
%  DispatchImage() extracts pixel data from an Image into a raw memory array.
631
%  The pixel data is written in scanline order top-to-bottom using an
632
%  arbitrary quantum order specified by 'map', and with quantum size
633
%  specified by 'type'.
634
%
635
%  The output array data may be unsigned char, unsigned short int, unsigned
636
%  int, unsigned long, float, or double.  Float and double require the pixels
637
%  to be normalized to the range [0..1], otherwise the range is [0..MaxVal]
638
%  where MaxVal is the maximum possible value for that type.
639
%
640
%  The method returns MagickPass on success or MagickFail if an error is
641
%  encountered.
642
%
643
%  Suppose we want want to extract the first scanline of a 640x480 image as
644
%  character data in red-green-blue order:
645
%
646
%      DispatchImage(image,0,0,640,1,"RGB",0,pixels,exception);
647
%
648
%  The format of the DispatchImage method is:
649
%
650
%      MagickPassFail DispatchImage(const Image *image,const long x_offset,
651
%        const long y_offset,const unsigned long columns,
652
%        const unsigned long rows,const char *map,const StorageType type,
653
%        void *pixels,ExceptionInfo *exception)
654
%
655
%  A description of each parameter follows:
656
%
657
%    o image: The image.
658
%
659
%    o x_offset, y_offset, columns, rows:  These values define the perimeter
660
%      of a region of pixels you want to extract.
661
%
662
%    o map: This string reflects the expected ordering of the pixel array.
663
%      It can be any combination or order of R = red, G = green, B = blue,
664
%      A = alpha  (same as Transparency), O = Opacity, T = Transparency,
665
%      C = cyan, Y = yellow, M = magenta, K = black, I = intensity (for
666
%      grayscale). Specify "P" = pad, to output a pad quantum. Pad quantums
667
%      are zero-value.
668
%
669
%    o type: Define the data type of the pixels.  Float and double types are
670
%      expected to be normalized [0..1] otherwise [0..MaxRGB].  Choose from
671
%      these types: CharPixel, ShortPixel, IntegerPixel, LongPixel, FloatPixel,
672
%      or DoublePixel.
673
%
674
%    o pixels: This array of values contain the pixel components as defined by
675
%      map and type.  You must preallocate this array where the expected
676
%      length varies depending on the values of width, height, map, and type.
677
%
678
%    o exception: Return any errors or warnings in this structure.
679
%
680
%
681
*/
682
MagickExport MagickPassFail DispatchImage(const Image *image,const long x_offset,
683
  const long y_offset,const unsigned long columns,const unsigned long rows,
684
  const char *map,const StorageType type,void *pixels,ExceptionInfo *exception)
685
0
{
686
0
  long
687
0
    y;
688
689
0
  register long
690
0
    i,
691
0
    x;
692
693
0
  register const PixelPacket
694
0
    * restrict p;
695
696
0
  register Quantum
697
0
    quantum;
698
699
0
  MapQuantumType
700
0
    switch_map[MaxTextExtent/sizeof(MapQuantumType)];
701
702
0
  size_t
703
0
    length;
704
705
0
  MagickPassFail
706
0
    status=MagickPass;
707
708
0
  assert(image != (Image *) NULL);
709
0
  assert(image->signature == MagickSignature);
710
711
  /*
712
    Handle a few common special cases in order to improve performance.
713
  */
714
0
  if (type == CharPixel)
715
0
    {
716
0
      DispatchType
717
0
        dispatch_type=UndefinedDispatchType;
718
719
0
      if (LocaleCompare(map,"BGR") == 0)
720
0
        dispatch_type=BGRDispatchType;
721
0
      else if (LocaleCompare(map,"BGRA") == 0)
722
0
        dispatch_type=BGRADispatchType;
723
0
      else if (LocaleCompare(map,"BGRP") == 0)
724
0
        dispatch_type=BGRPDispatchType;
725
0
      else if (LocaleCompare(map,"RGB") == 0)
726
0
        dispatch_type=RGBDispatchType;
727
0
      else if (LocaleCompare(map,"RGBA") == 0)
728
0
        dispatch_type=RGBADispatchType;
729
0
      else if (LocaleCompare(map,"I") == 0)
730
0
        dispatch_type=IDispatchType;
731
732
0
      if (dispatch_type != UndefinedDispatchType)
733
0
        {
734
0
          register unsigned char
735
0
            * restrict q = (unsigned char*) pixels;
736
737
0
          for (y=0; y < (long) rows; y++)
738
0
            {
739
0
              p=AcquireImagePixels(image,x_offset,y_offset+y,columns,1,exception);
740
0
              if (p == (const PixelPacket *) NULL)
741
0
                {
742
0
                  status=MagickFail;
743
0
                  break;
744
0
                }
745
746
0
              switch (dispatch_type)
747
0
                {
748
0
                case BGRDispatchType:
749
0
                  {
750
0
                    for (x=(long) columns; x != 0; x--)
751
0
                      {
752
0
                        *q++=ScaleQuantumToChar(GetBlueSample(p));
753
0
                        *q++=ScaleQuantumToChar(GetGreenSample(p));
754
0
                        *q++=ScaleQuantumToChar(GetRedSample(p));
755
0
                        p++;
756
0
                      }
757
0
                    break;
758
0
                  }
759
0
                case BGRADispatchType:
760
0
                  {
761
0
                    for (x=(long) columns; x != 0; x--)
762
0
                      {
763
0
                        *q++=ScaleQuantumToChar(GetBlueSample(p));
764
0
                        *q++=ScaleQuantumToChar(GetGreenSample(p));
765
0
                        *q++=ScaleQuantumToChar(GetRedSample(p));
766
0
                        *q++=ScaleQuantumToChar(MaxRGB-GetOpacitySample(p));
767
0
                        p++;
768
0
                      }
769
0
                    break;
770
0
                  }
771
0
                case BGRPDispatchType:
772
0
                  {
773
0
                    for (x=(long) columns; x != 0; x--)
774
0
                      {
775
0
                        *q++=ScaleQuantumToChar(GetBlueSample(p));
776
0
                        *q++=ScaleQuantumToChar(GetGreenSample(p));
777
0
                        *q++=ScaleQuantumToChar(GetRedSample(p));
778
0
                        *q++=0;
779
0
                        p++;
780
0
                      }
781
0
                    break;
782
0
                  }
783
0
                case RGBDispatchType:
784
0
                  {
785
0
                    for (x=(long) columns; x != 0; x--)
786
0
                      {
787
0
                        *q++=ScaleQuantumToChar(GetRedSample(p));
788
0
                        *q++=ScaleQuantumToChar(GetGreenSample(p));
789
0
                        *q++=ScaleQuantumToChar(GetBlueSample(p));
790
0
                        p++;
791
0
                      }
792
0
                    break;
793
0
                  }
794
0
                case RGBADispatchType:
795
0
                  {
796
0
                    for (x=(long) columns; x != 0; x--)
797
0
                      {
798
0
                        *q++=ScaleQuantumToChar(GetRedSample(p));
799
0
                        *q++=ScaleQuantumToChar(GetGreenSample(p));
800
0
                        *q++=ScaleQuantumToChar(GetBlueSample(p));
801
0
                        *q++=ScaleQuantumToChar(MaxRGB-GetOpacitySample(p));
802
0
                        p++;
803
0
                      }
804
0
                    break;
805
0
                  }
806
0
                case IDispatchType:
807
0
                  {
808
0
                    if (image->is_grayscale)
809
0
                      {
810
0
                        for (x=(long) columns; x != 0; x--)
811
0
                          {
812
0
                            *q++=ScaleQuantumToChar(GetGraySample(p));
813
0
                            p++;
814
0
                          }
815
0
                      }
816
0
                    else
817
0
                      {
818
0
                        for (x=(long) columns; x != 0; x--)
819
0
                          {
820
0
                            *q++=ScaleQuantumToChar(PixelIntensity(p));
821
0
                            p++;
822
0
                          }
823
0
                      }
824
0
                    break;
825
0
                  }
826
0
                case UndefinedDispatchType:
827
0
                  {
828
0
                  }
829
0
                }
830
0
            }
831
0
          return (status);
832
0
        }
833
0
    }
834
835
0
  length=strlen(map);
836
0
  length=Min(length,sizeof(switch_map)/sizeof(MapQuantumType));
837
838
  /*
839
    Prepare a validated and more efficient version of the map.
840
  */
841
0
  for (i=0; i < (long) length; i++)
842
0
    {
843
0
      switch ((int) toupper((int) map[i]))
844
0
        {
845
0
        case 'R':
846
0
          {
847
0
            switch_map[i]=RedMapQuantum;
848
0
            break;
849
0
          }
850
0
        case 'G':
851
0
          {
852
0
            switch_map[i]=GreenMapQuantum;
853
0
            break;
854
0
          }
855
0
        case 'B':
856
0
          {
857
0
            switch_map[i]=BlueMapQuanum;
858
0
            break;
859
0
          }
860
0
        case 'A':
861
0
        case 'T':
862
0
          {
863
0
            switch_map[i]=TransparencyMapQuantum;
864
0
            break;
865
0
          }
866
0
        case 'C':
867
0
          {
868
0
            switch_map[i]=RedMapQuantum;
869
0
            if (image->colorspace == CMYKColorspace)
870
0
              break;
871
0
            ThrowException(exception,OptionError,ColorSeparatedImageRequired,map);
872
0
            return(MagickFail);
873
0
          }
874
0
        case 'M':
875
0
          {
876
0
            switch_map[i]=GreenMapQuantum;
877
0
            if (image->colorspace == CMYKColorspace)
878
0
              break;
879
0
            ThrowException(exception,OptionError,ColorSeparatedImageRequired,map);
880
0
            return(MagickFail);
881
0
          }
882
0
        case 'Y':
883
0
          {
884
0
            switch_map[i]=BlueMapQuanum;
885
0
            if (image->colorspace == CMYKColorspace)
886
0
              break;
887
0
            ThrowException(exception,OptionError,ColorSeparatedImageRequired,map);
888
0
            return(MagickFail);
889
0
          }
890
0
        case 'K':
891
0
          {
892
0
            switch_map[i]=OpacityMapQuantum;
893
0
            if (image->colorspace == CMYKColorspace)
894
0
              break;
895
0
            ThrowException(exception,OptionError,ColorSeparatedImageRequired,map);
896
0
            return(MagickFail);
897
0
          }
898
0
        case 'I':
899
0
          {
900
0
            switch_map[i]=IntensityMapQuantum;
901
0
            break;
902
0
          }
903
0
        case 'O':
904
0
          {
905
0
            switch_map[i]=OpacityMapQuantum;
906
0
            break;
907
0
          }
908
0
        case 'P':
909
0
          {
910
0
            switch_map[i]=PadMapQuantum;
911
0
            break;
912
0
          }
913
0
        default:
914
0
          {
915
0
            ThrowException(exception,OptionError,UnrecognizedPixelMap,map);
916
0
            return(MagickFail);
917
0
          }
918
0
        }
919
0
    }
920
921
0
  for (y=0; y < (long) rows; y++)
922
0
    {
923
0
      p=AcquireImagePixels(image,x_offset,y_offset+y,columns,1,exception);
924
0
      if (p == (const PixelPacket *) NULL)
925
0
        {
926
0
          status=MagickFail;
927
0
          break;
928
0
        }
929
0
      for (x=0; x < (long) columns; x++)
930
0
        {
931
0
          for (i=0; i < (long) length; i++)
932
0
            {
933
              /*
934
                Obtain quantum value
935
              */
936
0
              quantum=0U;
937
0
              switch (switch_map[i])
938
0
                {
939
0
                case RedMapQuantum:
940
0
                  {
941
0
                    quantum=GetRedSample(p);
942
0
                    break;
943
0
                  }
944
0
                case GreenMapQuantum:
945
0
                  {
946
0
                    quantum=GetGreenSample(p);
947
0
                    break;
948
0
                  }
949
0
                case BlueMapQuanum:
950
0
                  {
951
0
                    quantum=GetBlueSample(p);
952
0
                    break;
953
0
                  }
954
0
                case IntensityMapQuantum:
955
0
                  {
956
0
                    if (image->is_grayscale)
957
0
                      {
958
0
                        quantum=GetRedSample(p);
959
0
                      }
960
0
                    else
961
0
                      {
962
0
                        double intensity = PixelIntensity(p);
963
0
                        quantum=RoundDoubleToQuantum(intensity);
964
0
                      }
965
0
                    break;
966
0
                  }
967
0
                case TransparencyMapQuantum:
968
0
                  {
969
0
                    if (image->matte)
970
0
                      quantum=GetOpacitySample(p);
971
0
                    quantum=MaxRGB-quantum;
972
0
                    break;
973
0
                  }
974
0
                case OpacityMapQuantum:
975
0
                  {
976
0
                    if ((image->matte) ||
977
0
                        (image->colorspace == CMYKColorspace))
978
0
                      quantum=GetOpacitySample(p);
979
0
                    break;
980
0
                  }
981
0
                case PadMapQuantum:
982
0
                  {
983
                    /* Zero quantum */
984
0
                    break;
985
0
                  }
986
0
                }
987
988
              /*
989
                Output quantum
990
              */
991
0
              switch (type)
992
0
                {
993
0
                case CharPixel:
994
0
                  {
995
0
                    register unsigned char *q = (unsigned char*) pixels;
996
0
                    *q++=ScaleQuantumToChar(quantum);
997
0
                    pixels=(void *) q;
998
0
                    break;
999
0
                  }
1000
0
                case ShortPixel:
1001
0
                  {
1002
0
                    register unsigned short *q = (unsigned short*) pixels;
1003
0
                    *q++=ScaleQuantumToShort(quantum);
1004
0
                    pixels=(void *) q;
1005
0
                    break;
1006
0
                  }
1007
0
                case IntegerPixel:
1008
0
                  {
1009
0
                    register unsigned int *q = (unsigned int*) pixels;
1010
0
                    *q++=ScaleQuantumToLong(quantum);
1011
0
                    pixels=(void *) q;
1012
0
                    break;
1013
0
                  }
1014
0
                case LongPixel:
1015
0
                  {
1016
0
                    register unsigned long *q = (unsigned long*) pixels;
1017
0
                    *q++=ScaleQuantumToLong(quantum);
1018
0
                    pixels=(void *) q;
1019
0
                    break;
1020
0
                  }
1021
0
                case FloatPixel:
1022
0
                  {
1023
0
                    register float *q = (float*) pixels;
1024
0
                    *q++=(float) ((double) quantum/MaxRGB);
1025
0
                    pixels=(void *) q;
1026
0
                    break;
1027
0
                  }
1028
0
                case DoublePixel:
1029
0
                  {
1030
0
                    register double *q = (double*) pixels;
1031
0
                    *q++=(double) quantum/MaxRGB;
1032
0
                    pixels=(void *) q;
1033
0
                    break;
1034
0
                  }
1035
0
                }
1036
0
            }
1037
0
          p++;
1038
0
        }
1039
0
    }
1040
0
  return(status);
1041
0
}
1042

1043
/*
1044
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1045
%                                                                             %
1046
%                                                                             %
1047
%                                                                             %
1048
+   M a g i c k F i n d R a w I m a g e M i n M a x                           %
1049
%                                                                             %
1050
%                                                                             %
1051
%                                                                             %
1052
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1053
%
1054
%  MagickFindRawImageMinMax() obtains the minimum and maximum sample values
1055
%  for a raw image.  The image blob must already be open with its current
1056
%  seek offset pointing to the start of the raw data.  The seek offset is
1057
%  restored when this function returns.  File data is processed on a
1058
%  scanline basis in order to minimize memory consumption.  The purpose of
1059
%  this function is to support pre-scanning a raw image to find its maximum
1060
%  values so that appropriate scaling may be applied when the data is read a
1061
%  second time. MagickFail is returned if a problem occurs while scanning the
1062
%  data.
1063
%
1064
%  The format of the MagickFindRawImageMinMax method is:
1065
%
1066
%      MagickPassFail MagickFindRawImageMinMax(Image *image, EndianType endian,
1067
%                   unsigned long width, unsigned long height,StorageType type,
1068
%                   unsigned scanline_octets, void *scanline_buffer,
1069
%                   double *min, double *max)
1070
%
1071
%  A description of each parameter follows:
1072
%
1073
%    o image: Pointer to an image with an already open blob, with seek
1074
%         offset pointing to raw data.
1075
%
1076
%    o endian: Endian order of raw data (LSBEndian or MSBEndian)
1077
%
1078
%    o width: Number of raw samples in a scanline.
1079
%
1080
%    o height: Number of scanlines to process.
1081
%
1082
%    o type: Raw data storage type.
1083
%
1084
%    o scanline_octets: Number of octets to read per scanline.
1085
%
1086
%    o scanline_buffer: Working buffer for scanlines.  Allocation size
1087
%         must at least be enough to contain scanline octets.
1088
%
1089
%    o min: Pointer to double value to update with minimum value.
1090
%
1091
%    o max: Pointer to double value to update with maximum value.
1092
%
1093
*/
1094
#define MagickFindMinMax(status,image,read_func,basic_type,scanline_octets,scanline_buffer,min,max) \
1095
2.05k
  {                                                                     \
1096
2.05k
    unsigned long                                                       \
1097
2.05k
      y;                                                                \
1098
2.05k
                                                                        \
1099
106k
    for (y = 0; y < height; y++)                                        \
1100
104k
      {                                                                 \
1101
104k
        unsigned long                                                   \
1102
104k
          x;                                                            \
1103
104k
                                                                        \
1104
104k
        basic_type                                                      \
1105
104k
          * restrict scanline;                                          \
1106
104k
                                                                        \
1107
104k
        scanline=(basic_type *) scanline_buffer;                        \
1108
104k
        if ((read_func)(image, scanline_octets, scanline) !=            \
1109
104k
            scanline_octets)                                            \
1110
104k
          {                                                             \
1111
502
            status=MagickFail;                                          \
1112
502
            break;                                                      \
1113
502
          }                                                             \
1114
104k
                                                                        \
1115
104k
        if (y == 0)                                                     \
1116
104k
          *min = *max = (double) scanline[0];                           \
1117
104k
                                                                        \
1118
8.28M
        for (x = 0; x < width; x++)                                     \
1119
8.18M
          {                                                             \
1120
8.18M
            if (*min > (double) scanline[x])                            \
1121
8.18M
              *min = (double) scanline[x];                              \
1122
8.18M
            if (*max < (double) scanline[x])                            \
1123
8.18M
              *max = (double) scanline[x];                              \
1124
8.18M
          }                                                             \
1125
104k
      }                                                                 \
1126
2.05k
  }
1127
1128
MagickPassFail
1129
MagickFindRawImageMinMax(Image *image, EndianType endian,
1130
                         unsigned long width, unsigned long height,StorageType type,
1131
                         unsigned scanline_octets, void *scanline_buffer,
1132
                         double *min, double *max)
1133
2.05k
{
1134
2.05k
  magick_off_t
1135
2.05k
    filepos;
1136
1137
2.05k
  MagickPassFail
1138
2.05k
    status;
1139
1140
2.05k
  *min=0.0;
1141
2.05k
  *max=1.0;
1142
2.05k
  status=MagickPass;
1143
1144
2.05k
  filepos = TellBlob(image);
1145
1146
2.05k
  if (filepos >= 0)
1147
2.05k
    {
1148
2.05k
      status=MagickPass;
1149
2.05k
      switch (type)
1150
2.05k
        {
1151
0
        case CharPixel:
1152
0
          {
1153
0
            size_t (*read_func)(Image * image, size_t octets, void *data);
1154
1155
0
            read_func = ReadBlob;
1156
1157
0
            MagickFindMinMax(status,image,read_func,char,scanline_octets,
1158
0
                             scanline_buffer,min,max);
1159
0
            break;
1160
0
          }
1161
0
        case ShortPixel:
1162
0
          {
1163
0
            size_t (*read_func)(Image * image, size_t octets, magick_uint16_t *data);
1164
1165
0
            if (endian == LSBEndian)
1166
0
              read_func = ReadBlobLSBShorts;
1167
0
            else
1168
0
              read_func = ReadBlobMSBShorts;
1169
1170
0
            MagickFindMinMax(status,image,read_func,magick_uint16_t,scanline_octets,
1171
0
                             scanline_buffer,min,max);
1172
0
            break;
1173
0
          }
1174
0
        case IntegerPixel:
1175
0
        case LongPixel:
1176
0
          {
1177
0
            size_t (*read_func)(Image * image, size_t octets, magick_uint32_t *data);
1178
1179
0
            if (endian == LSBEndian)
1180
0
              read_func = ReadBlobLSBLongs;
1181
0
            else
1182
0
              read_func = ReadBlobMSBLongs;
1183
1184
0
            MagickFindMinMax(status,image,read_func,magick_uint32_t,scanline_octets,
1185
0
                             scanline_buffer,min,max);
1186
0
            break;
1187
0
          }
1188
1.09k
        case FloatPixel:
1189
1.09k
          {
1190
1.09k
            size_t (*read_func)(Image * image, size_t octets, float *data);
1191
1192
1.09k
            if (endian == LSBEndian)
1193
312
              read_func = ReadBlobLSBFloats;
1194
785
            else
1195
785
              read_func = ReadBlobMSBFloats;
1196
1197
1.09k
            MagickFindMinMax(status,image,read_func,float,scanline_octets,
1198
1.09k
                             scanline_buffer,min,max);
1199
1.09k
            break;
1200
0
          }
1201
961
        case DoublePixel:
1202
961
          {
1203
961
            size_t (*read_func)(Image * image, size_t octets, double *data);
1204
1205
961
            if (endian == LSBEndian)
1206
381
              read_func = ReadBlobLSBDoubles;
1207
580
            else
1208
580
              read_func = ReadBlobMSBDoubles;
1209
1210
961
            MagickFindMinMax(status,image,read_func,double,scanline_octets,
1211
961
                             scanline_buffer,min,max);
1212
961
            break;
1213
0
          }
1214
2.05k
        }
1215
1216
2.05k
      if (SeekBlob(image, filepos, SEEK_SET) != filepos)
1217
0
        status = MagickFail;
1218
2.05k
    }
1219
1220
2.05k
  return status;
1221
2.05k
}
1222

1223
/*
1224
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1225
%                                                                             %
1226
%                                                                             %
1227
%                                                                             %
1228
+   M a g i c k G e t Q u a n t u m S a m p l e s P e r P i x e l             %
1229
%                                                                             %
1230
%                                                                             %
1231
%                                                                             %
1232
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1233
%
1234
%  MagickGetQuantumSamplesPerPixel() returns the number of discrete samples
1235
%  which will be encoded/decoded per-pixel for the specified QuantumType.
1236
%
1237
%  The format of the MagickGetQuantumSamplesPerPixel method is:
1238
%
1239
%      unsigned int MagickGetQuantumSamplesPerPixel(const QuantumType quantum_type)
1240
%
1241
%  A description of each parameter follows:
1242
%
1243
%    o quantum_type: Quantum type
1244
%
1245
%
1246
*/
1247
MagickExport unsigned int
1248
MagickGetQuantumSamplesPerPixel(const QuantumType quantum_type)
1249
34.3k
{
1250
34.3k
  unsigned int
1251
34.3k
    samples=0;
1252
1253
34.3k
  switch (quantum_type)
1254
34.3k
    {
1255
508
    case UndefinedQuantum:
1256
508
      samples=0;
1257
508
      break;
1258
107
    case IndexQuantum:
1259
107
      samples=1;
1260
107
      break;
1261
11.1k
    case GrayQuantum:
1262
11.1k
      samples=1;
1263
11.1k
      break;
1264
0
    case IndexAlphaQuantum:
1265
0
      samples=2;
1266
0
      break;
1267
731
    case GrayAlphaQuantum:
1268
731
      samples=2;
1269
731
      break;
1270
0
    case RedQuantum:
1271
0
      samples=1;
1272
0
      break;
1273
0
    case CyanQuantum:
1274
0
      samples=1;
1275
0
      break;
1276
0
    case GreenQuantum:
1277
0
      samples=1;
1278
0
      break;
1279
0
    case YellowQuantum:
1280
0
      samples=1;
1281
0
      break;
1282
0
    case BlueQuantum:
1283
0
      samples=1;
1284
0
      break;
1285
0
    case MagentaQuantum:
1286
0
      samples=1;
1287
0
      break;
1288
0
    case AlphaQuantum:
1289
0
      samples=1;
1290
0
      break;
1291
0
    case BlackQuantum:
1292
0
      samples=1;
1293
0
      break;
1294
19.5k
    case RGBQuantum:
1295
19.5k
      samples=3;
1296
19.5k
      break;
1297
703
    case RGBAQuantum:
1298
703
      samples=4;
1299
703
      break;
1300
925
    case CMYKQuantum:
1301
925
      samples=4;
1302
925
      break;
1303
760
    case CMYKAQuantum:
1304
760
      samples=5;
1305
760
      break;
1306
0
    case CIEYQuantum:
1307
0
      samples=1;
1308
0
      break;
1309
0
    case CIEXYZQuantum:
1310
0
      samples=3;
1311
0
      break;
1312
34.3k
    }
1313
1314
34.3k
  return samples;
1315
34.3k
}
1316

1317
/*
1318
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1319
%                                                                             %
1320
%                                                                             %
1321
%                                                                             %
1322
+   I n i t i a l i z e C o n s t i t u t e                                   %
1323
%                                                                             %
1324
%                                                                             %
1325
%                                                                             %
1326
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1327
%
1328
%  Method InitializeConstitute initializes the constitute facility
1329
%
1330
%  The format of the InitializeConstitute method is:
1331
%
1332
%      MagickPassFail InitializeConstitute(void)
1333
%
1334
%
1335
*/
1336
MagickPassFail
1337
InitializeConstitute(void)
1338
254
{
1339
254
  assert(constitute_semaphore == (SemaphoreInfo *) NULL);
1340
254
  constitute_semaphore=AllocateSemaphoreInfo();
1341
254
  return MagickPass;
1342
254
}
1343

1344
/*
1345
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1346
%                                                                             %
1347
%                                                                             %
1348
%                                                                             %
1349
%   P i n g I m a g e                                                         %
1350
%                                                                             %
1351
%                                                                             %
1352
%                                                                             %
1353
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1354
%
1355
%  PingImage() returns all the attributes of an image or image sequence
1356
%  except for the pixels.  It is much faster and consumes far less memory
1357
%  than ReadImage().  On failure, a NULL image is returned and exception
1358
%  describes the reason for the failure.
1359
%
1360
%  The format of the PingImage method is:
1361
%
1362
%      Image *PingImage(const ImageInfo *image_info,ExceptionInfo *exception)
1363
%
1364
%  A description of each parameter follows:
1365
%
1366
%    o image_info: Ping the image defined by the file or filename members of
1367
%      this structure.
1368
%
1369
%    o exception: Return any errors or warnings in this structure.
1370
%
1371
%
1372
*/
1373
MagickExport Image *PingImage(const ImageInfo *image_info,
1374
  ExceptionInfo *exception)
1375
0
{
1376
0
  Image
1377
0
    *image;
1378
1379
0
  ImageInfo
1380
0
    *clone_info;
1381
1382
0
  assert(image_info != (ImageInfo *) NULL);
1383
0
  assert(image_info->signature == MagickSignature);
1384
0
  assert(exception != (ExceptionInfo *) NULL);
1385
  /* SetExceptionInfo(exception,UndefinedException); */
1386
0
  clone_info=CloneImageInfo(image_info);
1387
0
  clone_info->ping=True;
1388
0
  image=ReadImage(clone_info,exception);
1389
0
  DestroyImageInfo(clone_info);
1390
  /*
1391
    Intentionally restart timer if ping is requested since timing ping
1392
    is meaningless and misleading.
1393
  */
1394
0
  if (image != (Image *) NULL)
1395
0
    GetTimerInfo(&image->timer);
1396
0
  return(image);
1397
0
}
1398

1399
/*
1400
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1401
%                                                                             %
1402
%                                                                             %
1403
%                                                                             %
1404
%   R e a d I m a g e                                                         %
1405
%                                                                             %
1406
%                                                                             %
1407
%                                                                             %
1408
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1409
%
1410
%  ReadImage() reads an image or image sequence from a file or file handle.
1411
%  The method returns a NULL if there is a memory shortage or if the image
1412
%  cannot be read.  On failure, a NULL image is returned and exception
1413
%  describes the reason for the failure.
1414
%
1415
%  The format of the ReadImage method is:
1416
%
1417
%      Image *ReadImage(const ImageInfo *image_info,ExceptionInfo *exception)
1418
%
1419
%  A description of each parameter follows:
1420
%
1421
%    o image_info: Read the image defined by the file or filename members of
1422
%      this structure.
1423
%
1424
%    o exception: Return any errors or warnings in this structure.
1425
%
1426
%
1427
*/
1428
static void RemoveTemporaryInputFile(ImageInfo *image_info)
1429
0
{
1430
0
  size_t
1431
0
    filename_length;
1432
1433
  /*
1434
    Remove normal file name.
1435
  */
1436
0
  if(!LiberateTemporaryFile(image_info->filename))
1437
0
    (void) remove(image_info->filename);
1438
1439
  /*
1440
    Remove a .cache file corresponding to a .mpc file.
1441
    This stupidity is necessary because MPC "files" are comprised of two
1442
    separate files.
1443
  */
1444
0
  filename_length=strlen(image_info->filename);
1445
0
  if ((filename_length > 4U) &&
1446
0
      (LocaleCompare(image_info->filename+filename_length-4,".mpc") == 0))
1447
0
    {
1448
0
      char remove_name[MaxTextExtent];
1449
0
      (void) strlcpy(remove_name,image_info->filename,sizeof(remove_name));
1450
0
      remove_name[filename_length-4]=0;
1451
0
      (void) strlcat(remove_name,".cache",sizeof(remove_name));
1452
0
      (void) printf("removing %s\n", remove_name);
1453
0
      (void) remove(remove_name);
1454
0
    }
1455
0
  else if (LocaleCompare(image_info->magick,"mpc") == 0)
1456
0
    {
1457
0
      char remove_name[MaxTextExtent];
1458
0
      (void) strlcpy(remove_name,image_info->filename,sizeof(remove_name));
1459
0
      (void) strlcat(remove_name,".cache",sizeof(remove_name));
1460
0
      (void) printf("removing %s\n", remove_name);
1461
0
      (void) remove(remove_name);
1462
0
    }
1463
1464
0
  errno=0;
1465
0
}
1466
1467
/*
1468
  Test if image list is a simple ordered list already in the bounds of
1469
  subimage/subrange or if it needs to be reconciled.
1470
*/
1471
static MagickBool MagickReconcileListNeeded(const Image* image, const ImageInfo *image_info) MAGICK_FUNC_PURE;
1472
static MagickBool MagickReconcileListNeeded(const Image* image, const ImageInfo *image_info)
1473
0
{
1474
0
  const Image
1475
0
    *list;
1476
1477
0
  const unsigned long
1478
0
    min_scene = image_info->subimage,
1479
0
    max_scene = image_info->subimage+image_info->subrange;
1480
1481
0
  MagickBool
1482
0
    res = MagickFalse;
1483
1484
0
  do
1485
0
    {
1486
0
      if (strchr(image_info->tile, ',') != (char *) NULL)
1487
0
        {
1488
0
          res=MagickTrue;
1489
0
          break;
1490
0
        }
1491
1492
0
      for (list = image; list != (Image *) NULL; list=list->next)
1493
0
        {
1494
0
          if (!(list->scene >= min_scene))
1495
0
            {
1496
0
              res=MagickTrue;
1497
0
              break;
1498
0
            }
1499
1500
0
          if (!(list->scene < max_scene))
1501
0
            {
1502
0
              res=MagickTrue;
1503
0
              break;
1504
0
            }
1505
1506
0
          if ((list->next) && (list->scene+1 != list->next->scene))
1507
0
            {
1508
0
              res=MagickTrue;
1509
0
              break;
1510
0
            }
1511
0
        }
1512
1513
0
    } while (0);
1514
1515
0
  return res;
1516
0
}
1517
1518
MagickExport Image *ReadImage(const ImageInfo *image_info,
1519
  ExceptionInfo *exception)
1520
6.18M
{
1521
6.18M
  char
1522
6.18M
    filename[MaxTextExtent],
1523
6.18M
    magick[MaxTextExtent];
1524
1525
6.18M
  const DelegateInfo
1526
6.18M
    *delegate_info;
1527
1528
6.18M
  const MagickInfo
1529
6.18M
    *magick_info;
1530
1531
6.18M
  Image
1532
6.18M
    *image,
1533
6.18M
    *next;
1534
1535
6.18M
  ImageInfo
1536
6.18M
    *clone_info;
1537
1538
  /*
1539
    Determine image type from filename prefix or suffix (e.g. image.jpg).
1540
  */
1541
6.18M
  assert(image_info != (ImageInfo *) NULL);
1542
6.18M
  assert(image_info->signature == MagickSignature);
1543
6.18M
  assert(image_info->filename != (char *) NULL);
1544
6.18M
  assert(exception != (ExceptionInfo *) NULL);
1545
  /* SetExceptionInfo(exception,UndefinedException); */
1546
6.18M
  if ((*image_info->filename == '@') && (!IsAccessibleNoLogging(image_info->filename)))
1547
0
    return(ReadImages(image_info,exception));
1548
6.18M
  clone_info=CloneImageInfo(image_info);
1549
1550
  /*
1551
    Obtain file magick from filename
1552
  */
1553
6.18M
  (void) SetImageInfo(clone_info,SETMAGICK_READ,exception);
1554
6.18M
  (void) LogMagickEvent(BlobEvent,GetMagickModule(),
1555
6.18M
                        "Magick=%s, Filename=%s", clone_info->magick,clone_info->filename);
1556
6.18M
  (void) strlcpy(filename,clone_info->filename,MaxTextExtent);
1557
6.18M
  (void) strlcpy(magick,clone_info->magick,MaxTextExtent);
1558
  /*
1559
    Call appropriate image reader based on image type.
1560
  */
1561
6.18M
  {
1562
6.18M
    ExceptionInfo
1563
6.18M
      module_exception,
1564
6.18M
      delegate_exception;
1565
1566
6.18M
    GetExceptionInfo(&module_exception);
1567
6.18M
    GetExceptionInfo(&delegate_exception);
1568
6.18M
    magick_info=GetMagickInfo(clone_info->magick,&module_exception);
1569
6.18M
    delegate_info=(const DelegateInfo *) NULL;
1570
6.18M
    if ((magick_info == (const MagickInfo *) NULL) ||
1571
6.18M
        (magick_info->decoder == NULL))
1572
292
      delegate_info=GetDelegateInfo(clone_info->magick,(char *) NULL,&delegate_exception);
1573
1574
6.18M
    if (((magick_info == (const MagickInfo *) NULL) ||
1575
6.18M
         (magick_info->decoder == NULL)) &&
1576
292
        ((delegate_info == (const DelegateInfo *) NULL) ||
1577
0
         (delegate_info->decode == NULL)))
1578
292
      {
1579
        /*
1580
          Module loader ConfigureError errors are intentionally
1581
          ignored here in order to provide the user with familiar "no
1582
          delegate" error messages.  This may be re-considered later.
1583
        */
1584
292
        if ((module_exception.severity != UndefinedException) &&
1585
0
            (module_exception.severity != ConfigureError))
1586
0
          CopyException(exception,&module_exception);
1587
292
        else if (delegate_exception.severity != UndefinedException)
1588
6
          CopyException(exception,&delegate_exception);
1589
286
        else
1590
286
          {
1591
            /*
1592
              Try to choose a useful error type
1593
            */
1594
286
            if (clone_info->filename[0] == 0)
1595
234
              {
1596
234
                errno=0;
1597
234
                ThrowException(exception,MissingDelegateError,
1598
234
                               NoDecodeDelegateForThisImageFormat,clone_info->magick);
1599
234
              }
1600
52
            else if (IsAccessibleAndNotEmpty(clone_info->filename))
1601
10
              {
1602
10
                errno=0;
1603
10
                ThrowException(exception,MissingDelegateError,
1604
10
                               NoDecodeDelegateForThisImageFormat,clone_info->filename);
1605
10
              }
1606
42
            else
1607
42
              {
1608
42
                ThrowException(exception,FileOpenError,UnableToOpenFile,
1609
42
                               clone_info->filename);
1610
42
              }
1611
286
          }
1612
292
        DestroyExceptionInfo(&module_exception);
1613
292
        DestroyExceptionInfo(&delegate_exception);
1614
292
        if (clone_info->temporary)
1615
0
          RemoveTemporaryInputFile(clone_info);
1616
292
        DestroyImageInfo(clone_info);
1617
292
        return((Image *) NULL);
1618
292
      }
1619
1620
6.18M
    DestroyExceptionInfo(&module_exception);
1621
6.18M
    DestroyExceptionInfo(&delegate_exception);
1622
6.18M
  }
1623
1624
6.18M
  if ((magick_info != (const MagickInfo *) NULL) &&
1625
6.18M
      (magick_info->seekable_stream == MagickTrue))
1626
3.76M
    {
1627
3.76M
      unsigned int
1628
3.76M
        status;
1629
1630
3.76M
      image=AllocateImage(clone_info);
1631
3.76M
      if (image == (Image *) NULL)
1632
0
        {
1633
0
          DestroyImageInfo(clone_info);
1634
0
          return((Image *) NULL);
1635
0
        }
1636
3.76M
      (void) strlcpy(image->filename,clone_info->filename,MaxTextExtent);
1637
3.76M
      status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
1638
3.76M
      if (status == False)
1639
0
        {
1640
0
          DestroyImageInfo(clone_info);
1641
0
          DestroyImage(image);
1642
0
          return((Image *) NULL);
1643
0
        }
1644
3.76M
      if (!BlobIsSeekable(image))
1645
0
        {
1646
          /*
1647
            Coder requires a random access stream.
1648
          */
1649
0
          if(!AcquireTemporaryFileName(clone_info->filename))
1650
0
            {
1651
0
              ThrowException(exception,FileOpenError,
1652
0
                UnableToCreateTemporaryFile,clone_info->filename);
1653
0
              CloseBlob(image);
1654
0
              DestroyImageInfo(clone_info);
1655
0
              DestroyImage(image);
1656
0
              return((Image *) NULL);
1657
0
            }
1658
0
          if (ImageToFile(image,clone_info->filename,exception) == MagickFail)
1659
0
            {
1660
0
              LiberateTemporaryFile(clone_info->filename);
1661
0
              CloseBlob(image);
1662
0
              DestroyImageInfo(clone_info);
1663
0
              DestroyImage(image);
1664
0
              return(MagickFail);
1665
0
            }
1666
0
          clone_info->temporary=True;
1667
0
        }
1668
3.76M
      CloseBlob(image);
1669
3.76M
      DestroyImage(image);
1670
3.76M
    }
1671
6.18M
  image=(Image *) NULL;
1672
6.18M
  if ((magick_info != (const MagickInfo *) NULL) &&
1673
6.18M
      (magick_info->decoder != NULL))
1674
6.18M
    {
1675
6.18M
      if (!magick_info->thread_support)
1676
1.31M
        LockSemaphoreInfo(constitute_semaphore);
1677
6.18M
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1678
6.18M
        "Invoking \"%.1024s\" decoder (%.1024s) subimage=%lu subrange=%lu",
1679
6.18M
                            magick_info->name,
1680
6.18M
                            magick_info->description,
1681
6.18M
                            clone_info->subimage,
1682
6.18M
                            clone_info->subrange);
1683
6.18M
      image=(magick_info->decoder)(clone_info,exception);
1684
6.18M
      if (!magick_info->thread_support)
1685
1.31M
        UnlockSemaphoreInfo(constitute_semaphore);
1686
1687
6.18M
      if (image != (Image *) NULL)
1688
745k
        {
1689
745k
          image=GetFirstImageInList(image);
1690
745k
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1691
745k
                                "Returned from \"%.1024s\" decoder: frames=%lu cache=%s"
1692
745k
                                " monochrome=%s grayscale=%s class=%s colorspace=%s",
1693
745k
                                magick_info->name,
1694
745k
                                GetImageListLength(image),
1695
745k
                                (GetPixelCachePresent(image) ? "present" : "missing"),
1696
745k
                                MagickBoolToString(image->is_monochrome),
1697
745k
                                MagickBoolToString(image->is_grayscale),
1698
745k
                                ClassTypeToString(image->storage_class),
1699
745k
                                ColorspaceTypeToString(image->colorspace));
1700
745k
        }
1701
5.44M
      else
1702
5.44M
        {
1703
5.44M
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1704
5.44M
                                "Returned from \"%.1024s\" decoder, returned image is NULL!",
1705
5.44M
                                magick_info->name);
1706
5.44M
          if (exception->severity < ErrorException)
1707
5.34k
            ThrowException(exception,CoderError,DecodedImageNotReturned,filename);
1708
5.44M
        }
1709
1710
      /*
1711
        Enforce that returned images do not have open blobs.
1712
      */
1713
6.18M
      if (image != (Image *) NULL)
1714
745k
        {
1715
745k
          assert(!GetBlobIsOpen(image));
1716
745k
        }
1717
1718
      /*
1719
        Deal with errors in the image which were not properly reported
1720
        to exception.  If there is an exception at error level, then
1721
        destroy image so that bad image is not consumed by user.
1722
      */
1723
6.18M
      if (image != (Image *) NULL)
1724
745k
        {
1725
745k
          GetImageException(image,exception);
1726
745k
          if (exception->severity >= ErrorException)
1727
525k
            {
1728
525k
              DestroyImageList(image);
1729
525k
              image=(Image *) NULL;
1730
525k
            }
1731
745k
        }
1732
6.18M
    }
1733
0
  else
1734
0
    {
1735
0
      if (delegate_info == (const DelegateInfo *) NULL)
1736
0
        {
1737
0
          if (clone_info->temporary)
1738
0
            RemoveTemporaryInputFile(clone_info);
1739
0
          DestroyImageInfo(clone_info);
1740
0
          return((Image *) NULL);
1741
0
        }
1742
      /*
1743
        Let our decoding delegate process the image.
1744
      */
1745
0
      image=AllocateImage(clone_info);
1746
0
      if (image == (Image *) NULL)
1747
0
        {
1748
0
          DestroyImageInfo(clone_info);
1749
0
          return((Image *) NULL);
1750
0
        }
1751
0
      (void) strlcpy(image->filename,clone_info->filename,MaxTextExtent);
1752
0
      if(!AcquireTemporaryFileName(clone_info->filename))
1753
0
        {
1754
0
          ThrowException(exception,FileOpenError,UnableToCreateTemporaryFile,
1755
0
            clone_info->filename);
1756
0
          DestroyImageInfo(clone_info);
1757
0
          return((Image *) NULL);
1758
0
        }
1759
0
      (void) InvokeDelegate(clone_info,image,clone_info->magick,(char *) NULL,
1760
0
        exception);
1761
0
      DestroyImageList(image);
1762
0
      image=(Image *) NULL;
1763
0
      clone_info->temporary=True;
1764
0
      (void) SetImageInfo(clone_info,SETMAGICK_READ,exception);
1765
0
      magick_info=GetMagickInfo(clone_info->magick,exception);
1766
      /*
1767
        If there is no magick info entry for this format, or there is
1768
        no decoder for the format, or an error is reported, then
1769
        attempt to return a reasonable error report.
1770
      */
1771
0
      if ((magick_info == (const MagickInfo *) NULL) ||
1772
0
          (magick_info->decoder == NULL) ||
1773
0
          (exception->severity != UndefinedException))
1774
0
        {
1775
0
          if (exception->severity == UndefinedException)
1776
0
          {
1777
0
            if (IsAccessibleAndNotEmpty(clone_info->filename))
1778
0
              ThrowException(exception,MissingDelegateError,
1779
0
                NoDecodeDelegateForThisImageFormat,clone_info->filename);
1780
0
            else
1781
0
              ThrowException(exception,FileOpenError,UnableToOpenFile,
1782
0
                clone_info->filename);
1783
0
          }
1784
0
          if (clone_info->temporary)
1785
0
            RemoveTemporaryInputFile(clone_info);
1786
0
          DestroyImageInfo(clone_info);
1787
0
          return((Image *) NULL);
1788
0
        }
1789
      /*
1790
        Invoke decoder for format
1791
      */
1792
0
      if (!magick_info->thread_support)
1793
0
        LockSemaphoreInfo(constitute_semaphore);
1794
0
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1795
0
        "Invoking \"%.1024s\" decoder (%.1024s) subimage=%lu subrange=%lu",
1796
0
                            magick_info->name,
1797
0
                            magick_info->description,
1798
0
                            clone_info->subimage,
1799
0
                            clone_info->subrange);
1800
0
      image=(magick_info->decoder)(clone_info,exception);
1801
0
      if (!magick_info->thread_support)
1802
0
        UnlockSemaphoreInfo(constitute_semaphore);
1803
1804
0
      if (image != (Image *) NULL)
1805
0
        {
1806
0
          image=GetFirstImageInList(image);
1807
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1808
0
                                "Returned from \"%.1024s\" decoder: frames=%lu"
1809
0
                                " cache=%s monochrome=%s grayscale=%s class=%s"
1810
0
                                " colorspace=%s",
1811
0
                                magick_info->name,
1812
0
                                GetImageListLength(image),
1813
0
                                (GetPixelCachePresent(image) ? "present" : "missing"),
1814
0
                                MagickBoolToString(image->is_monochrome),
1815
0
                                MagickBoolToString(image->is_grayscale),
1816
0
                                ClassTypeToString(image->storage_class),
1817
0
                                ColorspaceTypeToString(image->colorspace));
1818
0
        }
1819
0
      else
1820
0
        {
1821
0
          (void) LogMagickEvent(CoderEvent,GetMagickModule(),
1822
0
                                "Returned from \"%.1024s\" decoder: returned image is NULL!",
1823
0
                                magick_info->name);
1824
0
          if (exception->severity < ErrorException)
1825
0
            ThrowException(exception,CoderError,DecodedImageNotReturned,filename);
1826
0
        }
1827
1828
      /*
1829
        Enforce that returned images do not have open blobs.
1830
      */
1831
0
      if (image != (Image *) NULL)
1832
0
        {
1833
0
          assert(!GetBlobIsOpen(image));
1834
0
        }
1835
1836
      /*
1837
        Deal with errors in the image which were not properly reported
1838
        to exception.  If there is an exception at error level, then
1839
        destroy image so that bad image is not consumed by user.
1840
      */
1841
0
      if (image != (Image *) NULL)
1842
0
        {
1843
0
          GetImageException(image,exception);
1844
0
          if (exception->severity >= ErrorException)
1845
0
            {
1846
0
              DestroyImageList(image);
1847
0
              image=(Image *) NULL;
1848
0
            }
1849
0
        }
1850
1851
      /*
1852
        Restore original input file magick in case read is from a
1853
        temporary file prepared by an external delegate.  The user
1854
        will expect that the format reported is that of the input
1855
        file.
1856
      */
1857
0
      if (image != (Image *) NULL)
1858
0
        (void) strlcpy(image->magick,magick,MaxTextExtent);
1859
0
    }
1860
6.18M
  if (clone_info->temporary)
1861
0
    {
1862
0
      RemoveTemporaryInputFile(clone_info);
1863
0
      clone_info->temporary=False;
1864
0
      if (image != (Image *) NULL)
1865
0
        (void) strlcpy(image->filename,filename,MaxTextExtent);
1866
0
    }
1867
6.18M
  if (image == (Image *) NULL)
1868
5.96M
    {
1869
5.96M
      DestroyImageInfo(clone_info);
1870
5.96M
      return((Image *) NULL);
1871
5.96M
    }
1872
219k
  if (GetBlobTemporary(image))
1873
0
    RemoveTemporaryInputFile(clone_info);
1874
1875
219k
  if ((image->next != (Image *) NULL) && IsSubimage(clone_info->tile,False) &&
1876
0
      MagickReconcileListNeeded(image,clone_info))
1877
0
    {
1878
0
      char
1879
0
        *q;
1880
1881
0
      Image
1882
0
        *clone_image,
1883
0
        *subimages;
1884
1885
0
      long
1886
0
        quantum;
1887
1888
0
      register char
1889
0
        *p;
1890
1891
0
      register long
1892
0
        i;
1893
1894
0
      unsigned long
1895
0
        first,
1896
0
        last;
1897
1898
      /*
1899
        User specified subimages (e.g. image.miff[1,3-5,7-6,2]).
1900
      */
1901
0
      subimages=NewImageList();
1902
0
      p=clone_info->tile;
1903
0
      for (q=p; *q != '\0'; p++)
1904
0
      {
1905
0
        while (isspace((int) *p) || (*p == ','))
1906
0
          p++;
1907
0
        first=strtol(p,&q,10);
1908
0
        last=first;
1909
0
        while (isspace((int) *q))
1910
0
          q++;
1911
0
        if (*q == '-')
1912
0
          last=strtol(q+1,&q,10);
1913
0
        quantum=first > last ? -1 : 1;
1914
0
        for (p=q; first != (last+quantum); first+=quantum)
1915
0
        {
1916
0
          i=0;
1917
0
          for (next=image; next != (Image *) NULL; next=next->next)
1918
0
          {
1919
0
            if (next->scene != 0)
1920
0
              i=(long) next->scene;
1921
0
            if (i != (long) first)
1922
0
              {
1923
0
                i++;
1924
0
                continue;
1925
0
              }
1926
0
            clone_image=CloneImage(next,0,0,True,exception);
1927
0
            if (clone_image == (Image *) NULL)
1928
0
              break;
1929
0
            AppendImageToList(&subimages,clone_image);
1930
0
            i++;
1931
0
          }
1932
0
        }
1933
0
      }
1934
0
      if (subimages == (Image *) NULL)
1935
0
        ThrowException(exception,OptionError,
1936
0
                       SubimageSpecificationReturnsNoImages,
1937
0
                       clone_info->filename);
1938
0
      else
1939
0
        {
1940
0
          while (subimages->previous != (Image *) NULL)
1941
0
            subimages=subimages->previous;
1942
0
          DestroyImageList(image);
1943
0
          image=subimages;
1944
0
        }
1945
0
    }
1946
461k
  for (next=image; next; next=next->next)
1947
242k
  {
1948
#if 0
1949
    /*
1950
      Apply user-requested colorspace setting.  This allows the user
1951
      to override the default colorspace for the image type.
1952
      FIXME: Does not work yet.
1953
    */
1954
    {
1955
      const ImageAttribute
1956
        *attribute;
1957
1958
/*       if ((image_info->attributes) && */
1959
/*           (attribute=GetImageAttribute(image_info->attributes,"colorspace-override"))) */
1960
      if ((attribute=GetImageAttribute(image,"colorspace-override")))
1961
        {
1962
          next->colorspace = StringToColorspaceType(attribute->value);
1963
          (void) LogMagickEvent(TransformEvent,GetMagickModule(),
1964
                                "Colorspace explicitly set to %s",
1965
                                ColorspaceTypeToString(image->colorspace));
1966
        }
1967
    }
1968
#endif
1969
242k
    if (next->storage_class == PseudoClass)
1970
61.0k
      {
1971
        /*
1972
          Check and cache monochrome and grayscale status
1973
        */
1974
61.0k
        (void) IsMonochromeImage(next,exception);
1975
61.0k
        if (next->is_monochrome)
1976
13.6k
          next->is_grayscale=True;
1977
47.4k
        else
1978
47.4k
          (void) IsGrayImage(next,exception);
1979
61.0k
      }
1980
242k
    next->taint=False;
1981
242k
    (void) strlcpy(next->magick_filename,filename,MaxTextExtent);
1982
242k
    if (GetBlobTemporary(image))
1983
0
      (void) strlcpy(next->filename,filename,MaxTextExtent);
1984
242k
    if (next->magick_columns == 0)
1985
221k
      next->magick_columns=next->columns;
1986
242k
    if (next->magick_rows == 0)
1987
221k
      next->magick_rows=next->rows;
1988
242k
    if (next->page.width == 0)
1989
198k
      next->page.width=next->columns;
1990
242k
    if (next->page.height == 0)
1991
198k
      next->page.height=next->rows;
1992
242k
  }
1993
219k
  DestroyImageInfo(clone_info);
1994
219k
  return(image);
1995
6.18M
}
1996

1997
/*
1998
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1999
%                                                                             %
2000
%                                                                             %
2001
%                                                                             %
2002
+   R e a d I m a g e s                                                       %
2003
%                                                                             %
2004
%                                                                             %
2005
%                                                                             %
2006
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2007
%
2008
%  ReadImages() reads a list of image names from a file and then returns the
2009
%  images as a linked list.
2010
%
2011
%  The format of the ReadImage method is:
2012
%
2013
%      Image *ReadImages(const ImageInfo *image_info,ExceptionInfo *exception)
2014
%
2015
%  A description of each parameter follows:
2016
%
2017
%    o image: Method ReadImage returns a pointer to the image after
2018
%      reading.  A null image is returned if there is a memory shortage or
2019
%      if the image cannot be read.
2020
%
2021
%    o image_info: The list of filenames are defined in the filename member of
2022
%      this structure.
2023
%
2024
%    o exception: Return any errors or warnings in this structure.
2025
%
2026
%
2027
*/
2028
static Image *ReadImages(const ImageInfo *image_info,ExceptionInfo *exception)
2029
0
{
2030
0
  char
2031
0
    *command,
2032
0
    **images;
2033
2034
0
  Image
2035
0
    *image;
2036
2037
0
  ImageInfo
2038
0
    *clone_info;
2039
2040
0
  int
2041
0
    number_images;
2042
2043
0
  register Image
2044
0
    *next;
2045
2046
0
  register long
2047
0
    i;
2048
2049
0
  size_t
2050
0
    length;
2051
2052
  /*
2053
    Read image list from a file.
2054
  */
2055
0
  assert(image_info != (ImageInfo *) NULL);
2056
0
  assert(image_info->signature == MagickSignature);
2057
0
  assert(exception != (ExceptionInfo *) NULL);
2058
0
  command=(char *) FileToBlob(image_info->filename+1,&length,exception);
2059
0
  if (command == (char *) NULL)
2060
0
    return((Image *) NULL);
2061
0
  (void) MagickStripString(command);
2062
0
  images=StringToArgv(command,&number_images);
2063
0
  MagickFreeMemory(command);
2064
0
  if (images == (char **) NULL)
2065
0
    return((Image *) NULL);
2066
  /*
2067
    Read the images into a linked list.
2068
  */
2069
0
  image=(Image *) NULL;
2070
0
  clone_info=CloneImageInfo(image_info);
2071
0
  for (i=1; i < number_images; i++)
2072
0
  {
2073
0
    (void) strlcpy(clone_info->filename,images[i],MaxTextExtent);
2074
0
    if ((image_info->filename[0] == '@') &&
2075
0
        (clone_info->filename[0] == '@') &&
2076
0
        (strcmp(clone_info->filename+1,image_info->filename+1) == 0))
2077
0
      continue;
2078
0
    next=ReadImage(clone_info,exception);
2079
0
    if (next == (Image *) NULL)
2080
0
      continue;
2081
0
    if (image == (Image *) NULL)
2082
0
      image=next;
2083
0
    else
2084
0
      {
2085
0
        register Image
2086
0
          *q;
2087
2088
        /*
2089
          Link image into image list.
2090
        */
2091
0
        for (q=image; q->next != (Image *) NULL; q=q->next);
2092
0
        next->previous=q;
2093
0
        q->next=next;
2094
0
      }
2095
0
  }
2096
0
  DestroyImageInfo(clone_info);
2097
0
  for (i=0; i < number_images; i++)
2098
0
    MagickFreeMemory(images[i]);
2099
0
  MagickFreeMemory(images);
2100
0
  return(image);
2101
0
}
2102

2103
/*
2104
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2105
%                                                                             %
2106
%                                                                             %
2107
%                                                                             %
2108
%   R e a d I n l i n e I m a g e                                             %
2109
%                                                                             %
2110
%                                                                             %
2111
%                                                                             %
2112
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2113
%
2114
%  ReadInlineImage() reads a Base64-encoded inline image or image sequence.
2115
%  The method returns a NULL if there is a memory shortage or if the image
2116
%  cannot be read.  On failure, a NULL image is returned and exception
2117
%  describes the reason for the failure.
2118
%
2119
%  The format of the ReadInlineImage method is:
2120
%
2121
%      Image *ReadInlineImage(const ImageInfo *image_info,const char *content,
2122
%        ExceptionInfo *exception)
2123
%
2124
%  A description of each parameter follows:
2125
%
2126
%    o image_info: The image info.
2127
%
2128
%    o content: The image encoded in Base64.
2129
%
2130
%    o exception: Return any errors or warnings in this structure.
2131
%
2132
%
2133
*/
2134
MagickExport Image *ReadInlineImage(const ImageInfo *image_info,
2135
  const char *content,ExceptionInfo *exception)
2136
35.1k
{
2137
35.1k
  Image
2138
35.1k
    *image;
2139
2140
35.1k
  MonitorHandler
2141
35.1k
    handler;
2142
2143
35.1k
  unsigned char
2144
35.1k
    *blob;
2145
2146
35.1k
  size_t
2147
35.1k
    length;
2148
2149
35.1k
  register const char
2150
35.1k
    *p;
2151
2152
  /* SetExceptionInfo(exception,UndefinedException); */
2153
35.1k
  image=(Image *) NULL;
2154
2.74M
  for (p=content; (*p != ',') && (*p != '\0'); p++);
2155
35.1k
  if (*p == '\0')
2156
34.9k
    ThrowReaderException(CorruptImageError,CorruptImage,image);
2157
34.9k
  p++;
2158
34.9k
  blob=Base64Decode(p,&length);
2159
34.9k
  if (length == 0)
2160
255
    {
2161
255
      MagickFreeMemory(blob);
2162
255
      ThrowReaderException(CorruptImageError,CorruptImage,image);
2163
0
    }
2164
34.7k
  handler=SetMonitorHandler((MonitorHandler) NULL);
2165
34.7k
  image=BlobToImage(image_info,blob,length,exception);
2166
34.7k
  (void) SetMonitorHandler(handler);
2167
34.7k
  MagickFreeMemory(blob);
2168
34.7k
  return(image);
2169
34.9k
}
2170

2171
/*
2172
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2173
%                                                                             %
2174
%                                                                             %
2175
%                                                                             %
2176
%   W r i t e I m a g e                                                       %
2177
%                                                                             %
2178
%                                                                             %
2179
%                                                                             %
2180
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2181
%
2182
%  Use WriteImage() to write an image or an image sequence to a file or
2183
%  filehandle.  If writing to a file on disk, the name is defined by the
2184
%  filename member of the image structure.  WriteImage() returns
2185
%  MagickFailure is there is a memory shortage or if the image cannot be
2186
%  written.  Check the exception member of image to determine the cause
2187
%  for any failure.
2188
%
2189
%  The format of the WriteImage method is:
2190
%
2191
%      MagickPassFail WriteImage(const ImageInfo *image_info,Image *image)
2192
%
2193
%  A description of each parameter follows:
2194
%
2195
%    o image_info: The image info.
2196
%
2197
%    o image: The image.
2198
%
2199
%
2200
*/
2201
MagickExport MagickPassFail
2202
WriteImage(const ImageInfo *image_info,Image *image)
2203
96.6k
{
2204
96.6k
  const DelegateInfo
2205
96.6k
    *delegate_info;
2206
2207
96.6k
  const MagickInfo
2208
96.6k
    *magick_info;
2209
2210
96.6k
  ImageInfo
2211
96.6k
    *clone_info;
2212
2213
96.6k
  MagickPassFail
2214
96.6k
    status;
2215
2216
  /*
2217
    Determine image type from filename prefix or suffix (e.g. image.jpg).
2218
  */
2219
96.6k
  assert(image_info != (ImageInfo *) NULL);
2220
96.6k
  assert(image_info->signature == MagickSignature);
2221
96.6k
  assert(image_info->filename != (char *) NULL);
2222
96.6k
  assert(image != (Image *) NULL);
2223
96.6k
  assert(image->signature == MagickSignature);
2224
96.6k
  if (LocaleNCompare(image_info->magick,"INFO",sizeof("INFO")-1))
2225
96.6k
      GetTimerInfo(&image->timer);
2226
96.6k
  image->logging=IsEventLogged(CoderEvent);
2227
96.6k
  clone_info=CloneImageInfo(image_info);
2228
96.6k
  (void) strlcpy(clone_info->filename,image->filename,MaxTextExtent);
2229
96.6k
  (void) strlcpy(clone_info->magick,image->magick,MaxTextExtent);
2230
96.6k
  (void) SetImageInfo(clone_info,SETMAGICK_WRITE,&image->exception);
2231
96.6k
  (void) strlcpy(image->filename,clone_info->filename,MaxTextExtent);
2232
96.6k
  image->dither=image_info->dither;
2233
96.6k
  DisassociateBlob(image);
2234
2235
#if 0
2236
  /*
2237
    This bi-modal delegate code allows short-circuiting GraphicsMagick
2238
    in case the delegates support a direct translation.  For example,
2239
    PDF to PS using Ghostscript.
2240
2241
    This is currently disabled due to potential side-effects.
2242
  */
2243
  if (((image->next == (Image *) NULL) || clone_info->adjoin) &&
2244
      (image->previous == (Image *) NULL) &&
2245
      (clone_info->page == (char *) NULL) && !IsTaintImage(image))
2246
    {
2247
      delegate_info=GetDelegateInfo(image->magick,clone_info->magick,
2248
                                    &image->exception);
2249
      if ((delegate_info != (const DelegateInfo *) NULL) &&
2250
          (delegate_info->mode == 0) && IsAccessible(image->magick_filename))
2251
        {
2252
          /*
2253
            Let our bi-modal delegate process the image.
2254
          */
2255
          (void) strlcpy(image->filename,image->magick_filename,
2256
                         MaxTextExtent);
2257
          status=InvokeDelegate(clone_info,image,image->magick,
2258
                                clone_info->magick,&image->exception);
2259
          DestroyImageInfo(clone_info);
2260
          return(!status);
2261
        }
2262
    }
2263
#endif
2264
2265
  /*
2266
    Call appropriate image writer based on image type.
2267
  */
2268
96.6k
  status=MagickFail;
2269
96.6k
  magick_info=GetMagickInfo(clone_info->magick,&image->exception);
2270
96.6k
  if ((magick_info != (const MagickInfo *) NULL) &&
2271
96.6k
      (magick_info->encoder != NULL))
2272
96.6k
    {
2273
96.6k
      char
2274
96.6k
        tempfile[MaxTextExtent];
2275
2276
96.6k
      tempfile[0]='\0';
2277
2278
96.6k
      if (magick_info->seekable_stream == MagickTrue)
2279
61.3k
        {
2280
          /*
2281
            Divert output to temporary file if coder requires a
2282
            seekable stream and output is not seekable.
2283
          */
2284
61.3k
          if (OpenBlob(clone_info,image,WriteBinaryBlobMode,&image->exception))
2285
61.3k
            {
2286
61.3k
              if (!BlobIsSeekable(image))
2287
0
                {
2288
0
                  if(!AcquireTemporaryFileName(tempfile))
2289
0
                    {
2290
0
                      ThrowException(&image->exception,FileOpenError,
2291
0
                                     UnableToCreateTemporaryFile,image->filename);
2292
0
                      DestroyImageInfo(clone_info);
2293
0
                      return(MagickFail);
2294
0
                    }
2295
0
                  (void) strlcpy(image->filename,tempfile,sizeof(image->filename));
2296
0
                }
2297
61.3k
              else
2298
61.3k
                {
2299
                  /*
2300
                    OpenBlob may expand image->filename so we need to restore it.
2301
                  */
2302
61.3k
                  (void) strlcpy(image->filename,clone_info->filename,sizeof(image->filename));
2303
61.3k
                }
2304
61.3k
              CloseBlob(image);
2305
61.3k
            }
2306
61.3k
        }
2307
2308
96.6k
      if (!magick_info->thread_support)
2309
32.3k
        LockSemaphoreInfo(constitute_semaphore);
2310
96.6k
      if (image->logging)
2311
0
        (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2312
0
                              "Invoking \"%.1024s\" encoder (%.1024s): "
2313
0
                              "cache=%s "
2314
0
                              "adjoin=%s type=%s monochrome=%s grayscale=%s "
2315
0
                              "class=%s colorspace=%s",
2316
0
                              magick_info->name,
2317
0
                              magick_info->description,
2318
0
                              (GetPixelCachePresent(image) ? "present" : "missing"),
2319
0
                              MagickBoolToString(clone_info->adjoin),
2320
0
                              ImageTypeToString(clone_info->type),
2321
0
                              MagickBoolToString(image->is_monochrome),
2322
0
                              MagickBoolToString(image->is_grayscale),
2323
0
                              ClassTypeToString(image->storage_class),
2324
0
                              ColorspaceTypeToString(image->colorspace));
2325
96.6k
      status=(magick_info->encoder)(clone_info,image);
2326
96.6k
      (void) LogMagickEvent(CoderEvent,GetMagickModule(),
2327
96.6k
                            "Returned from \"%.1024s\" encoder, %s",magick_info->name,
2328
96.6k
                            (status == MagickFail ? "Failed" :"Succeeded"));
2329
96.6k
      if (!magick_info->thread_support)
2330
32.3k
        UnlockSemaphoreInfo(constitute_semaphore);
2331
2332
96.6k
      if (tempfile[0] != '\0')
2333
0
        {
2334
          /*
2335
            Send temporary file to stream.
2336
          */
2337
0
          (void) strlcpy(image->filename,clone_info->filename,MaxTextExtent);
2338
0
          if ((status &= OpenBlob(clone_info,image,WriteBinaryBlobMode,
2339
0
                                  &image->exception)))
2340
0
            {
2341
0
              status &= WriteBlobFile(image,tempfile);
2342
0
              CloseBlob(image);
2343
0
            }
2344
0
          LiberateTemporaryFile(tempfile);
2345
0
        }
2346
96.6k
    }
2347
25
  else
2348
25
    {
2349
25
      delegate_info=GetDelegateInfo((char *) NULL,clone_info->magick,
2350
25
                                    &image->exception);
2351
25
      if (delegate_info != (DelegateInfo *) NULL)
2352
0
        {
2353
          /*
2354
            Let our encoding delegate process the image.
2355
          */
2356
0
          if(!AcquireTemporaryFileName(image->filename))
2357
0
            {
2358
0
              ThrowException(&image->exception,FileOpenError,
2359
0
                             UnableToCreateTemporaryFile,image->filename);
2360
0
              DestroyImageInfo(clone_info);
2361
0
              return(MagickFail);
2362
0
            }
2363
0
          status=InvokeDelegate(clone_info,image,(char *) NULL,
2364
0
                                clone_info->magick,&image->exception);
2365
0
          (void) LiberateTemporaryFile(image->filename);
2366
0
          DestroyImageInfo(clone_info);
2367
0
          return(!status);
2368
0
        }
2369
25
      magick_info=GetMagickInfo(clone_info->magick,&image->exception);
2370
25
      if (!clone_info->affirm && (magick_info == (const MagickInfo *) NULL))
2371
0
        magick_info=(MagickInfo *)
2372
0
          GetMagickInfo(image->magick,&image->exception);
2373
25
      if ((magick_info == (MagickInfo *) NULL) ||
2374
25
          (magick_info->encoder == NULL))
2375
25
        {
2376
25
          ThrowException(&image->exception,MissingDelegateError,
2377
25
                         NoEncodeDelegateForThisImageFormat,
2378
25
                         clone_info->magick);
2379
25
          DestroyImageInfo(clone_info);
2380
25
          return(MagickFail);
2381
25
        }
2382
0
      if (!magick_info->thread_support)
2383
0
        LockSemaphoreInfo(constitute_semaphore);
2384
0
      status=(magick_info->encoder)(clone_info,image);
2385
0
      if (!magick_info->thread_support)
2386
0
        UnlockSemaphoreInfo(constitute_semaphore);
2387
0
    }
2388
96.6k
  (void) strlcpy(image->magick,clone_info->magick,MaxTextExtent);
2389
96.6k
  DestroyImageInfo(clone_info);
2390
96.6k
  if (GetBlobStatus(image))
2391
827
    {
2392
827
      int
2393
827
        first_errno;
2394
2395
827
      first_errno=GetBlobFirstErrno(image);
2396
827
      if (first_errno != 0)
2397
827
        errno=first_errno;
2398
827
      ThrowBinaryException(CorruptImageError,AnErrorHasOccurredWritingToFile,
2399
827
                           image->filename);
2400
0
    }
2401
95.8k
  return(status);
2402
96.6k
}
2403

2404
/*
2405
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2406
%                                                                             %
2407
%                                                                             %
2408
%                                                                             %
2409
%   W r i t e I m a g e s                                                     %
2410
%                                                                             %
2411
%                                                                             %
2412
%                                                                             %
2413
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2414
%
2415
%  WriteImages() writes an image sequence into one or more files.  While
2416
%  WriteImage() will also write an image sequence, it is limited to writing
2417
%  the sequence into a single file using a format which supports multiple
2418
%  frames.  WriteImages() does not have that limitation since it will
2419
%  generate multiple output files if necessary (or when requested).  When
2420
%  ImageInfo's adjoin flag is set to MagickFalse, the file name is expected
2421
%  to include a printf-style formatting string for the frame number (e.g.
2422
%  "image%02d.miff") so that the frames may be written.
2423
%
2424
%  The format of the WriteImages method is:
2425
%
2426
%      MagickPassFail WriteImages(const ImageInfo *image_info,
2427
%                                 Image *image,
2428
%                                 const char *filename,
2429
%                                 ExceptionInfo *exception)
2430
%
2431
%  A description of each parameter follows:
2432
%
2433
%    o image_info: The image info.
2434
%
2435
%    o images: The image list.
2436
%
2437
%    o filename: The image filename.
2438
%
2439
%    o exception: Return any errors or warnings in this structure.
2440
%
2441
%
2442
*/
2443
MagickExport MagickPassFail
2444
WriteImages(const ImageInfo *image_info,Image *image,
2445
            const char *filename,ExceptionInfo *exception)
2446
0
{
2447
0
  ImageInfo
2448
0
    *clone_info;
2449
2450
0
  unsigned int
2451
0
    status=MagickPass;
2452
2453
  /*
2454
    Write converted images.
2455
  */
2456
0
  assert(image_info != (const ImageInfo *) NULL);
2457
0
  assert(image_info->signature == MagickSignature);
2458
0
  assert(image != (Image *) NULL);
2459
0
  assert(image->signature == MagickSignature);
2460
0
  assert(exception != (ExceptionInfo *) NULL);
2461
0
  image->logging=IsEventLogged(CoderEvent);
2462
0
  clone_info=CloneImageInfo(image_info);
2463
0
  if (clone_info)
2464
0
    {
2465
0
      register Image
2466
0
        *p;
2467
2468
0
      if (filename != (const char *) NULL)
2469
0
        {
2470
0
          if (strlcpy(clone_info->filename,filename,MaxTextExtent) >= MaxTextExtent)
2471
0
            status &= MagickFail;
2472
          /* Set file name in all image frames */
2473
0
          for (p=image; p != (Image *) NULL; p=p->next)
2474
0
            if (p->filename != filename)
2475
0
              if (strlcpy(p->filename,filename,MaxTextExtent) >= MaxTextExtent)
2476
0
                status &= MagickFail;
2477
0
        }
2478
0
      (void) SetImageInfo(clone_info,
2479
0
                          (SETMAGICK_WRITE |
2480
0
                           (!clone_info->adjoin ? SETMAGICK_RECTIFY : 0U)),
2481
0
                          exception);
2482
0
      for (p=image; p != (Image *) NULL; p=p->next)
2483
0
        {
2484
0
          status &= WriteImage(clone_info,p);
2485
0
          if (p->exception.severity > exception->severity)
2486
0
            CopyException(exception,&p->exception);
2487
0
          GetImageException(p,exception);
2488
0
          if (clone_info->adjoin)
2489
0
            break;
2490
0
        }
2491
0
      if (clone_info->verbose)
2492
0
        (void) DescribeImage(image,stderr,False);
2493
0
      DestroyImageInfo(clone_info);
2494
0
      clone_info=0;
2495
0
    }
2496
0
  return(status);
2497
0
}
2498
2499
/*
2500
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2501
%                                                                             %
2502
%                                                                             %
2503
%                                                                             %
2504
%   W r i t e I m a g e s F i l e                                             %
2505
%                                                                             %
2506
%                                                                             %
2507
%                                                                             %
2508
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2509
%
2510
%  WriteImagesFile() writes an image or image sequence to a stdio
2511
%  FILE handle.  This may be used to append an encoded image to an already
2512
%  existing appended image sequence if the file seek position is at the end
2513
%  of an existing file.
2514
%
2515
%  The format of the WriteImagesFile method is:
2516
%
2517
%      unsigned int WriteImagesFile(const ImageInfo *image_info,Image *image,
2518
%                                   FILE *file,ExceptionInfo *exception)
2519
%
2520
%  A description of each parameter follows:
2521
%
2522
%    o image_info: The image info.
2523
%
2524
%    o images: The image list.
2525
%
2526
%    o file: The open (and positioned) file handle.
2527
%
2528
%    o exception: Return any errors or warnings in this structure.
2529
%
2530
%
2531
*/
2532
MagickExport MagickPassFail WriteImagesFile(const ImageInfo *image_info,Image *image,
2533
                                            FILE * file ,ExceptionInfo *exception)
2534
0
{
2535
0
  ImageInfo
2536
0
    *clone_info;
2537
2538
0
  unsigned int
2539
0
    status=MagickPass;
2540
2541
  /*
2542
    Write converted images.
2543
  */
2544
0
  assert(image_info != (const ImageInfo *) NULL);
2545
0
  assert(image_info->signature == MagickSignature);
2546
0
  assert(image != (Image *) NULL);
2547
0
  assert(image->signature == MagickSignature);
2548
0
  assert(exception != (ExceptionInfo *) NULL);
2549
0
  image->logging=IsEventLogged(CoderEvent);
2550
0
  clone_info=CloneImageInfo(image_info);
2551
0
  if (clone_info)
2552
0
    {
2553
0
      register Image
2554
0
        *p;
2555
2556
0
      clone_info->file=file;
2557
0
      (void) SetImageInfo(clone_info,
2558
0
                          (SETMAGICK_WRITE |
2559
0
                           (!clone_info->adjoin ? SETMAGICK_RECTIFY : 0U)),
2560
0
                          exception);
2561
0
      for (p=image; p != (Image *) NULL; p=p->next)
2562
0
        {
2563
0
          status &= WriteImage(clone_info,p);
2564
0
          if(p->exception.severity > exception->severity)
2565
0
            CopyException(exception,&p->exception);
2566
0
          GetImageException(p,exception);
2567
0
          if (clone_info->adjoin)
2568
0
            break;
2569
0
        }
2570
0
      if (clone_info->verbose)
2571
0
        (void) DescribeImage(image,stderr,False);
2572
0
      clone_info->file=0;
2573
0
      DestroyImageInfo(clone_info);
2574
0
      clone_info=0;
2575
0
    }
2576
0
  return(status);
2577
0
}