Coverage Report

Created: 2026-05-24 07:45

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/graphicsmagick/magick/channel.c
Line
Count
Source
1
/*
2
% Copyright (C) 2004-2026 GraphicsMagick Group
3
%
4
% This program is covered by multiple licenses, which are described in
5
% Copyright.txt. You should have received a copy of Copyright.txt with this
6
% package; otherwise see http://www.graphicsmagick.org/www/Copyright.html.
7
%
8
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9
%                                                                             %
10
%                                                                             %
11
%                                                                             %
12
%            CCCC  H   H   AAA   N   N  N   N  EEEEE  L                       %
13
%           C      H   H  A   A  NN  N  NN  N  E      L                       %
14
%           C      HHHHH  AAAAA  N N N  N N N  EEE    L                       %
15
%           C      H   H  A   A  N  NN  N  NN  E      L                       %
16
%            CCCC  H   H  A   A  N   N  N   N  EEEEE  LLLLL                   %
17
%                                                                             %
18
%                                                                             %
19
%                       Image Channel Operations                              %
20
%                                                                             %
21
%                                                                             %
22
%                           Software Design                                   %
23
%                           Bob Friesenhahn                                   %
24
%                             July  2004                                      %
25
%                                                                             %
26
%                                                                             %
27
%                                                                             %
28
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
29
%
30
%
31
%
32
*/
33

34
/*
35
  Include declarations.
36
*/
37
#include "magick/studio.h"
38
#include "magick/channel.h"
39
#include "magick/enum_strings.h"
40
#include "magick/image.h"
41
#include "magick/operator.h"
42
#include "magick/pixel_iterator.h"
43
#include "magick/utility.h"
44

45
/*
46
    Verify that image colorspace is compatible with with requested
47
    channel type.  Only check mismatch between RGB and CMYK since user
48
    might intentionally export some obscure colorspace channel.  We
49
    don't silently convert between RGB and CMYK since there is no one
50
    correct transform, and the transform is lossy.
51
  */
52
static MagickPassFail ValidateChannelRequest(const ColorspaceType image_colorspace,
53
                                             const ChannelType channel,
54
                                             ExceptionInfo *exception)
55
0
{
56
0
  MagickPassFail
57
0
    status = MagickPass;
58
59
0
  switch(channel)
60
0
    {
61
0
    case CyanChannel:
62
0
    case MagentaChannel:
63
0
    case YellowChannel:
64
0
    case BlackChannel:
65
0
      if (image_colorspace != CMYKColorspace)
66
0
        status = MagickFail;
67
0
      break;
68
0
    case RedChannel:
69
0
    case GreenChannel:
70
0
    case BlueChannel:
71
0
      if (image_colorspace == CMYKColorspace)
72
0
        status = MagickFail;;
73
0
      break;
74
0
    default:
75
0
      {
76
0
      }
77
0
    }
78
79
0
  if (MagickFail == status)
80
0
    ThrowException3(exception,ImageError,UnableToHandleImageChannel,ImageColorspaceMismatch);
81
82
0
  return status;
83
0
}
84

85
/*
86
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
87
%                                                                             %
88
%                                                                             %
89
%                                                                             %
90
%     C h a n n e l I m a g e                                                 %
91
%                                                                             %
92
%                                                                             %
93
%                                                                             %
94
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
95
%
96
%  Transform an image so that the resulting image is a grayscale image
97
%  based on a specified image channel. The resulting image is returned in
98
%  the RGB colorspace. This function does not force or assume an input
99
%  image colorspace so it may be used to extract channels from images in
100
%  colorspaces other than RGB or CMYK. For example, if the image is currently
101
%  transformed to the HWB colorspace, the 'B' channel may be extracted by
102
%  specifying RedChannel as the ChannelType argument.
103
%
104
%  The format of the ChannelImage method is:
105
%
106
%      unsigned int ChannelImage(Image *image,const ChannelType channel)
107
%
108
%  A description of each parameter follows:
109
%
110
%    o image: The image.
111
%
112
%    o channel: Identify which channel to extract: Red, Cyan, Green, Magenta,
113
%    Blue, Yellow, or Opacity.
114
%
115
%
116
*/
117
static MagickPassFail
118
ChannelImagePixels(void *mutable_data,            /* User provided mutable data */
119
                   const void *immutable_data,    /* User provided immutable data */
120
                   Image * restrict image,        /* Modify image */
121
                   PixelPacket * restrict pixels, /* Pixel row */
122
                   IndexPacket * restrict indexes,/* Pixel row indexes */
123
                   const long npixels,            /* Number of pixels in row */
124
                   ExceptionInfo *exception)      /* Exception report */
125
0
{
126
  /*
127
    Transform image so that it only represents the specified channel.
128
  */
129
0
  ChannelType
130
0
    channel = *((const ChannelType *) immutable_data);
131
132
0
  register long
133
0
    i;
134
135
0
  ARG_NOT_USED(mutable_data);
136
0
  ARG_NOT_USED(exception);
137
138
0
  switch (channel)
139
0
    {
140
0
    case RedChannel:
141
0
    case CyanChannel:
142
0
      {
143
0
        for (i=0; i < npixels; i++)
144
0
          {
145
0
            pixels[i].green=pixels[i].red;
146
0
            pixels[i].blue=pixels[i].red;
147
0
            pixels[i].opacity=OpaqueOpacity;
148
0
          }
149
0
        break;
150
0
      }
151
0
    case GreenChannel:
152
0
    case MagentaChannel:
153
0
      {
154
0
        for (i=0; i < npixels; i++)
155
0
          {
156
0
            pixels[i].red=pixels[i].green;
157
0
            pixels[i].blue=pixels[i].green;
158
0
            pixels[i].opacity=OpaqueOpacity;
159
0
          }
160
0
        break;
161
0
      }
162
0
    case BlueChannel:
163
0
    case YellowChannel:
164
0
      {
165
0
        for (i=0; i < npixels; i++)
166
0
          {
167
0
            pixels[i].red=pixels[i].blue;
168
0
            pixels[i].green=pixels[i].blue;
169
0
            pixels[i].opacity=OpaqueOpacity;
170
0
          }
171
0
        break;
172
0
      }
173
0
    case MatteChannel:
174
0
    case OpacityChannel:
175
0
      {
176
0
        if (image->colorspace == CMYKColorspace)
177
0
          {
178
0
            for (i=0; i < npixels; i++)
179
0
              {
180
0
                pixels[i].red=indexes[i];
181
0
                pixels[i].green=indexes[i];
182
0
                pixels[i].blue=indexes[i];
183
0
                pixels[i].opacity=OpaqueOpacity;
184
0
              }
185
0
          }
186
0
        else
187
0
          {
188
0
            for (i=0; i < npixels; i++)
189
0
              {
190
0
                pixels[i].red=pixels[i].opacity;
191
0
                pixels[i].green=pixels[i].opacity;
192
0
                pixels[i].blue=pixels[i].opacity;
193
0
                pixels[i].opacity=OpaqueOpacity;
194
0
              }
195
0
          }
196
0
        image->matte=False;
197
0
        break;
198
0
      }
199
0
    case BlackChannel:
200
0
      {
201
0
        for (i=0; i < npixels; i++)
202
0
          {
203
0
            pixels[i].red=pixels[i].opacity;
204
0
            pixels[i].green=pixels[i].opacity;
205
0
            pixels[i].blue=pixels[i].opacity;
206
0
            pixels[i].opacity=OpaqueOpacity;
207
0
          }
208
0
        image->matte=False;
209
0
        break;
210
0
      }
211
212
0
    case UndefinedChannel:
213
0
    case AllChannels:
214
0
    case GrayChannel:
215
0
      {
216
0
        for (i=0; i < npixels; i++)
217
0
          {
218
0
            pixels[i].red=pixels[i].green=pixels[i].blue=PixelIntensity(&pixels[i]);
219
0
            pixels[i].opacity=OpaqueOpacity;
220
0
          }
221
0
        image->matte=False;
222
0
        break;
223
0
      }
224
0
    }
225
226
0
  return MagickPass;
227
0
}
228
MagickExport MagickPassFail ChannelImage(Image *image,const ChannelType channel)
229
0
{
230
0
  char
231
0
    progress_message[MaxTextExtent];
232
233
0
  ChannelType
234
0
    channel_type = channel;
235
236
0
  MagickPassFail
237
0
    status=MagickPass;
238
239
  /*
240
    Channel DirectClass packets.
241
  */
242
0
  assert(image != (Image *) NULL);
243
0
  assert(image->signature == MagickSignature);
244
245
0
  MagickFormatString(progress_message,sizeof(progress_message),
246
0
                     "[%%s] Extract %s channel...  ",
247
0
                     ChannelTypeToString(channel));
248
249
  /*
250
    Verify that image colorspace is compatible with with requested
251
    channel type.
252
  */
253
0
  if (ValidateChannelRequest(image->colorspace,channel,&image->exception)
254
0
      == MagickFail)
255
0
    return MagickFail;
256
257
0
  image->storage_class=DirectClass;
258
0
  status=PixelIterateMonoModify(ChannelImagePixels,
259
0
                                NULL,
260
0
                                progress_message,
261
0
                                NULL,&channel_type,0,0,image->columns,image->rows,
262
0
                                image,&image->exception);
263
264
0
  image->matte=MagickFalse;
265
0
  image->is_grayscale=MagickTrue;
266
0
  image->colorspace=RGBColorspace;
267
268
0
  return(status);
269
0
}
270

271
/*
272
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
273
%                                                                             %
274
%                                                                             %
275
%                                                                             %
276
%     E x p o r t I m a g e C h a n n e l                                     %
277
%                                                                             %
278
%                                                                             %
279
%                                                                             %
280
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
281
%
282
%  ExportImageChannel() exports a specified image channel as a new image.
283
%
284
%  The format of the ExportImageChannel method is:
285
%
286
%      Image *ExportImageChannel(const Image *image,
287
%                                const ChannelType channel,
288
%                                ExceptionInfo *exception)
289
%
290
%  A description of each parameter follows:
291
%
292
%    o image: The source image.
293
%
294
%    o channel: The image channel to export
295
%
296
%    o exception: Return any errors or warnings in this structure.
297
%
298
%
299
*/
300
#define EXPORT_CHANNEL(source)                                          \
301
0
  do {                                                                  \
302
0
    register long                                                       \
303
0
      i;                                                                \
304
0
                                                                        \
305
0
    if (source_image->storage_class == PseudoClass)                     \
306
0
      {                                                                 \
307
0
        for (i=0; i < npixels; i++)                                     \
308
0
          {                                                             \
309
0
            new_pixels[i].red=new_pixels[i].green=new_pixels[i].blue=   \
310
0
              source_image->colormap[source_indexes[i]].source;         \
311
0
            new_pixels[i].opacity=OpaqueOpacity;                        \
312
0
          }                                                             \
313
0
      }                                                                 \
314
0
    else                                                                \
315
0
      {                                                                 \
316
0
        for (i=0; i < npixels; i++)                                     \
317
0
          {                                                             \
318
0
            new_pixels[i].red=new_pixels[i].green=new_pixels[i].blue=   \
319
0
              source_pixels[i].source;                                  \
320
0
            new_pixels[i].opacity=OpaqueOpacity;                        \
321
0
          }                                                             \
322
0
      }                                                                 \
323
0
  } while (0);
324
325
static MagickPassFail
326
ExportImageChannelPixels(void *mutable_data,                /* User provided mutable data */
327
                         const void *immutable_data,        /* User provided immutable data */
328
                         const Image * restrict source_image,         /* Source image */
329
                         const PixelPacket * restrict source_pixels,  /* Pixel row in source image */
330
                         const IndexPacket * restrict source_indexes, /* Pixel row indexes in source image */
331
                         Image * restrict new_image,                  /* New image */
332
                         PixelPacket * restrict new_pixels,           /* Pixel row in new image */
333
                         IndexPacket * restrict new_indexes,          /* Pixel row indexes in new image */
334
                         const long npixels,                /* Number of pixels in row */
335
                         ExceptionInfo *exception           /* Exception report */
336
                         )
337
0
{
338
0
  ChannelType
339
0
    channel = *((const ChannelType *) immutable_data);
340
341
0
  ARG_NOT_USED(mutable_data);
342
0
  ARG_NOT_USED(new_image);
343
0
  ARG_NOT_USED(new_indexes);
344
0
  ARG_NOT_USED(exception);
345
346
0
  switch (channel)
347
0
    {
348
0
    case RedChannel:
349
0
    case CyanChannel:
350
0
      {
351
0
        EXPORT_CHANNEL(red);
352
0
        break;
353
0
      }
354
0
    case GreenChannel:
355
0
    case MagentaChannel:
356
0
      {
357
0
        EXPORT_CHANNEL(green);
358
0
        break;
359
0
      }
360
0
    case BlueChannel:
361
0
    case YellowChannel:
362
0
      {
363
0
        EXPORT_CHANNEL(blue);
364
0
        break;
365
0
      }
366
0
    case MatteChannel:
367
0
    case OpacityChannel:
368
0
      {
369
0
        if (source_image->colorspace == CMYKColorspace)
370
0
          {
371
0
            register long
372
0
              i;
373
374
0
            for (i=0; i < npixels; i++)
375
0
              {
376
0
                new_pixels[i].red=new_pixels[i].green=
377
0
                  new_pixels[i].blue=source_indexes[i];
378
0
                new_pixels[i].opacity=OpaqueOpacity;
379
0
              }
380
0
          }
381
0
        else
382
0
          {
383
0
            EXPORT_CHANNEL(opacity);
384
0
          }
385
0
        break;
386
0
      }
387
0
    case BlackChannel:
388
0
      {
389
0
        EXPORT_CHANNEL(opacity);
390
0
        break;
391
0
      }
392
0
    default:
393
0
      {
394
0
      }
395
0
    }
396
397
0
  return MagickPass;
398
0
}
399
0
#define ExportImageChannelText "[%s] Exporting channel...  "
400
MagickExport Image *ExportImageChannel(const Image *source_image,
401
                                       const ChannelType channel,
402
                                       ExceptionInfo *exception)
403
0
{
404
0
  ChannelType
405
0
    channel_type = channel;
406
407
0
  Image
408
0
    *new_image;
409
410
0
  assert(source_image != (Image *) NULL);
411
0
  assert(source_image->signature == MagickSignature);
412
0
  assert(exception != (ExceptionInfo *) NULL);
413
0
  assert(exception->signature == MagickSignature);
414
415
  /*
416
    Verify that image colorspace is compatible with with requested
417
    channel type.
418
  */
419
0
  if (ValidateChannelRequest(source_image->colorspace,channel,exception)
420
0
      == MagickFail)
421
0
    return (Image *) NULL;
422
423
0
  new_image=CloneImage(source_image,source_image->columns,source_image->rows,
424
0
                       True,exception);
425
0
  if (new_image == (Image *) NULL)
426
0
    return ((Image *) NULL);
427
428
0
  new_image->storage_class=DirectClass;
429
430
0
  (void) PixelIterateDualNew(ExportImageChannelPixels,
431
0
                             NULL,
432
0
                             ExportImageChannelText,
433
0
                             NULL,&channel_type,
434
0
                             source_image->columns,source_image->rows,
435
0
                             source_image,0,0,
436
0
                             new_image,0,0,
437
0
                             exception);
438
439
0
  new_image->is_grayscale=True;
440
0
  new_image->is_monochrome=source_image->is_monochrome;
441
0
  return new_image;
442
0
}
443

444
/*
445
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
446
%                                                                             %
447
%                                                                             %
448
%                                                                             %
449
%   G e t I m a g e C h a n n e l D e p t h                                   %
450
%                                                                             %
451
%                                                                             %
452
%                                                                             %
453
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
454
%
455
%  GetImageChannelDepth() returns the minimum bit depth required to store
456
%  the specified image channel without actual loss of color resolution.
457
%  Pixel components are stored in a Quantum, which is 8, 16, or 32 bits
458
%  depending on the QuantumDepth value set when the software is compiled.
459
%  GetImageChannelDepth() returns the smallest modulus storage size which
460
%  supports the scale of the pixel within the range (i.e. no information is
461
%  lost). As an example, the value one is returned for a bilevel channel
462
%  since only one bit of resolution is required to represent a bilevel channel.
463
%
464
%  The format of the GetImageChannelDepth method is:
465
%
466
%      unsigned long GetImageChannelDepth(const Image *image,
467
%                      const ChannelType channel,ExceptionInfo *exception)
468
%
469
%  A description of each parameter follows:
470
%
471
%    o image: The image.
472
%
473
%    o channel: Channel to test.
474
%
475
%    o exception: Return any errors or warnings in this structure.
476
%
477
%
478
*/
479
0
#define ComputeChannelDepthText "[%s] Get channel depth..."
480
481
#define CHANNEL_DEPTH(parameter)                                \
482
0
  {                                                             \
483
0
    register long                                               \
484
0
      i;                                                        \
485
0
                                                                \
486
0
    register unsigned int                                       \
487
0
      scale;                                                    \
488
0
                                                                \
489
0
    if (depth < 1)                                              \
490
0
      depth=1;                                                  \
491
0
    scale=MaxRGB / (MaxRGB >> (QuantumDepth-depth));            \
492
0
    i=0;                                                        \
493
0
    while (i < npixels)                                         \
494
0
      {                                                         \
495
0
        if ((parameter) != scale*((parameter)/scale))           \
496
0
          {                                                     \
497
0
            depth++;                                            \
498
0
            if (depth == QuantumDepth)                          \
499
0
              break;                                            \
500
0
            scale=MaxRGB / (MaxRGB >> (QuantumDepth-depth));    \
501
0
            continue;                                           \
502
0
          }                                                     \
503
0
        i++;                                                    \
504
0
      }                                                         \
505
0
  }
506
507
static MagickPassFail
508
GetImageChannelDepthPixels(void *mutable_data,          /* User provided mutable data */
509
                           const void *immutable_data,  /* User provided immutable data */
510
                           const Image * restrict image,          /* Input image */
511
                           const PixelPacket * restrict pixels,   /* Pixel row */
512
                           const IndexPacket * restrict indexes,  /* Pixel indexes */
513
                           const long npixels,          /* Number of pixels in row */
514
                           ExceptionInfo *exception     /* Exception report */
515
                           )
516
0
{
517
0
  unsigned int
518
0
    *channel_depth=(unsigned int *) mutable_data;
519
520
0
  ChannelType
521
0
    channel = *((const ChannelType *) immutable_data);
522
523
0
  register unsigned int
524
0
    depth;
525
526
0
  ARG_NOT_USED(exception);
527
528
#if defined(HAVE_OPENMP)
529
#  pragma omp critical (GM_GetImageChannelDepthPixels)
530
#endif
531
0
  {
532
0
    depth=*channel_depth;
533
0
  }
534
535
0
  switch (channel)
536
0
    {
537
0
    case RedChannel:
538
0
    case CyanChannel:
539
0
      {
540
0
        CHANNEL_DEPTH(pixels[i].red);
541
0
        break;
542
0
      }
543
0
    case GreenChannel:
544
0
    case MagentaChannel:
545
0
      {
546
0
        CHANNEL_DEPTH(pixels[i].green);
547
0
        break;
548
0
      }
549
0
    case BlueChannel:
550
0
    case YellowChannel:
551
0
      {
552
0
        CHANNEL_DEPTH(pixels[i].blue);
553
0
        break;
554
0
      }
555
0
    case MatteChannel:
556
0
    case OpacityChannel:
557
0
      {
558
0
        if (image->colorspace == CMYKColorspace)
559
0
          {
560
0
            CHANNEL_DEPTH(indexes[i]);
561
0
          }
562
0
        else
563
0
          {
564
0
            CHANNEL_DEPTH(pixels[i].opacity);
565
0
          }
566
0
        break;
567
0
      }
568
0
    case BlackChannel:
569
0
      {
570
0
        CHANNEL_DEPTH(pixels[i].opacity);
571
0
        break;
572
0
      }
573
0
    default:
574
0
      {
575
0
      }
576
0
    }
577
578
#if defined(HAVE_OPENMP)
579
#  pragma omp critical (GM_GetImageChannelDepthPixels)
580
#endif
581
0
  {
582
0
    if (depth > *channel_depth)
583
0
      *channel_depth=depth;
584
0
  }
585
586
0
  if (depth >= QuantumDepth)
587
0
    return MagickFail;
588
589
0
  return MagickPass;
590
0
}
591
592
MagickExport unsigned int
593
GetImageChannelDepth(const Image *image,
594
                     const ChannelType channel,
595
                     ExceptionInfo *exception)
596
0
{
597
0
  unsigned int
598
0
    depth;
599
600
0
  assert(image != (Image *) NULL);
601
0
  assert(image->signature == MagickSignature);
602
603
0
  depth=1;
604
605
0
  (void) PixelIterateMonoRead(GetImageChannelDepthPixels,
606
0
                              NULL,
607
0
                              ComputeChannelDepthText,
608
0
                              &depth,
609
0
                              &channel,
610
0
                              0,0,image->columns,image->rows,
611
0
                              image,exception);
612
0
  return depth;
613
0
}
614

615
/*
616
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
617
%                                                                             %
618
%                                                                             %
619
%                                                                             %
620
%     I m p o r t I m a g e C h a n n e l                                     %
621
%                                                                             %
622
%                                                                             %
623
%                                                                             %
624
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
625
%
626
%  ImportImageChannel() imports an image into the specified image channel.
627
%
628
%  The format of the ImportImageChannel method is:
629
%
630
%      MagickPassFail ImportImageChannel(const Image *source_image,
631
%                                        Image *update_image,
632
%                                        const ChannelType channel)
633
%
634
%  A description of each parameter follows:
635
%
636
%    o source_image: The image to use as the replacement image channel.
637
%
638
%    o update_image: The image to import the channel into.
639
%
640
%    o channel: The image channel to import
641
%
642
%
643
*/
644
#define IMPORT_CHANNEL(target)                                          \
645
0
  do                                                                    \
646
0
    {                                                                   \
647
0
      register long                                                     \
648
0
        i;                                                              \
649
0
                                                                        \
650
0
      if (source_image->storage_class == PseudoClass)                   \
651
0
        {                                                               \
652
0
          if (source_image->is_grayscale)                               \
653
0
            for (i=0; i < npixels; i++)                                 \
654
0
              target=source_image->colormap[source_indexes[i]].red;     \
655
0
          else                                                          \
656
0
            for (i=0; i < npixels; i++)                                 \
657
0
              target=PixelIntensityToQuantum(&source_image->colormap[source_indexes[i]]); \
658
0
        }                                                               \
659
0
      else                                                              \
660
0
        {                                                               \
661
0
          if (source_image->is_grayscale)                               \
662
0
            for (i=0; i < npixels; i++)                                 \
663
0
              target=source_pixels[i].red;                              \
664
0
          else                                                          \
665
0
            for (i=0; i < npixels; i++)                                 \
666
0
              target=PixelIntensityToQuantum(&source_pixels[i]);        \
667
0
        }                                                               \
668
0
    } while (0);
669
670
static MagickPassFail
671
ImportImageChannelPixels(void *mutable_data,                /* User provided mutable data */
672
                         const void *immutable_data,        /* User provided immutable data */
673
                         const Image * restrict source_image,         /* Source image */
674
                         const PixelPacket * restrict source_pixels,  /* Pixel row in source image */
675
                         const IndexPacket * restrict source_indexes, /* Pixel row indexes in source image */
676
                         Image * restrict update_image,               /* Update image */
677
                         PixelPacket * restrict update_pixels,        /* Pixel row in update image */
678
                         IndexPacket * restrict update_indexes,       /* Pixel row indexes in update image */
679
                         const long npixels,                /* Number of pixels in row */
680
                         ExceptionInfo *exception           /* Exception report */
681
                         )
682
0
{
683
0
  ChannelType
684
0
    channel = *((const ChannelType *) immutable_data);
685
686
0
  ARG_NOT_USED(mutable_data);
687
0
  ARG_NOT_USED(exception);
688
689
0
  switch (channel)
690
0
    {
691
0
    case RedChannel:
692
0
    case CyanChannel:
693
0
      {
694
0
        IMPORT_CHANNEL(update_pixels[i].red);
695
0
        break;
696
0
      }
697
0
    case GreenChannel:
698
0
    case MagentaChannel:
699
0
      {
700
0
        IMPORT_CHANNEL(update_pixels[i].green);
701
0
        break;
702
0
      }
703
0
    case BlueChannel:
704
0
    case YellowChannel:
705
0
      {
706
0
        IMPORT_CHANNEL(update_pixels[i].blue);
707
0
        break;
708
0
      }
709
0
    case MatteChannel:
710
0
    case OpacityChannel:
711
0
      {
712
0
        if (update_image->colorspace == CMYKColorspace)
713
0
          {
714
0
            IMPORT_CHANNEL(update_indexes[i]);
715
0
          }
716
0
        else
717
0
          {
718
0
            IMPORT_CHANNEL(update_pixels[i].opacity);
719
0
          }
720
0
        break;
721
0
      }
722
0
    case BlackChannel:
723
0
      {
724
0
        IMPORT_CHANNEL(update_pixels[i].opacity);
725
0
        break;
726
0
      }
727
0
    default:
728
0
      {
729
0
      }
730
0
    }
731
732
0
  return MagickPass;
733
0
}
734
735
0
#define ImportImageChannelText  "[%s] Importing channel..."
736
MagickPassFail ImportImageChannel(const Image *source_image,
737
                                  Image *update_image,
738
                                  const ChannelType channel)
739
0
{
740
0
  ChannelType
741
0
    channel_type = channel;
742
743
0
  MagickPassFail
744
0
    status=MagickPass;
745
746
0
  assert(update_image != (Image *) NULL);
747
0
  assert(update_image->signature == MagickSignature);
748
0
  assert(source_image != (Image *) NULL);
749
0
  assert(source_image->signature == MagickSignature);
750
751
  /*
752
    Verify that image colorspace is compatible with with requested
753
    channel type.
754
  */
755
0
  if (ValidateChannelRequest(update_image->colorspace,channel,&update_image->exception)
756
0
      == MagickFail)
757
0
    return MagickFail;
758
759
0
  update_image->storage_class=DirectClass;
760
0
  status=PixelIterateDualModify(ImportImageChannelPixels,
761
0
                                NULL,
762
0
                                ImportImageChannelText,
763
0
                                NULL,&channel_type,
764
0
                                source_image->columns,source_image->rows,
765
0
                                source_image,0,0,
766
0
                                update_image,0,0,
767
0
                                &update_image->exception);
768
0
  return(status);
769
0
}
770

771
/*
772
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
773
%                                                                             %
774
%                                                                             %
775
%                                                                             %
776
%     I m p o r t I m a g e C h a n n e l s M a s k e d                       %
777
%                                                                             %
778
%                                                                             %
779
%                                                                             %
780
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
781
%
782
%  ImportImageChannelsMasked() imports all the channels from a source
783
%  image to an update image, except for the channels specified.
784
%
785
%  The format of the ImportImageChannelsMasked method is:
786
%
787
%      MagickPassFail ImportImageChannelsMasked(const Image *source_image,
788
%                                        Image *update_image,
789
%                                        const ChannelType channels)
790
%
791
%  A description of each parameter follows:
792
%
793
%    o source_image: The image from which to extract the replacement channels.
794
%
795
%    o update_image: The image to import the channels into.
796
%
797
%    o channel: The image channel to import
798
%
799
%
800
*/
801
static MagickPassFail
802
ImportImageChannelsMaskedPixels(void *mutable_data,                /* User provided mutable data */
803
                                const void *immutable_data,        /* User provided immutable data */
804
                                const Image * restrict source_image,         /* Source image */
805
                                const PixelPacket * restrict source_pixels,  /* Pixel row in source image */
806
                                const IndexPacket * restrict source_indexes, /* Pixel row indexes in source image */
807
                                Image * restrict update_image,               /* Update image */
808
                                PixelPacket * restrict update_pixels,        /* Pixel row in update image */
809
                                IndexPacket * restrict update_indexes,       /* Pixel row indexes in update image */
810
                                const long npixels,                /* Number of pixels in row */
811
                                ExceptionInfo *exception           /* Exception report */
812
                                )
813
0
{
814
0
  ChannelType
815
0
    channels = *((const ChannelType *) immutable_data);
816
817
0
  register long
818
0
    i;
819
820
0
  ARG_NOT_USED(mutable_data);
821
0
  ARG_NOT_USED(source_image);
822
0
  ARG_NOT_USED(exception);
823
824
0
  if (IsCMYKColorspace(update_image->colorspace))
825
0
    {
826
0
      if (!MagickChannelEnabled(channels,CyanChannel))
827
0
        for (i=0 ; i < npixels; i++)
828
0
          SetCyanSample(&update_pixels[i],GetCyanSample(&source_pixels[i]));
829
0
      if (!MagickChannelEnabled(channels,MagentaChannel))
830
0
        for (i=0 ; i < npixels; i++)
831
0
          SetMagentaSample(&update_pixels[i],GetMagentaSample(&source_pixels[i]));
832
0
      if (!MagickChannelEnabled(channels,YellowChannel))
833
0
        for (i=0 ; i < npixels; i++)
834
0
          SetYellowSample(&update_pixels[i],GetYellowSample(&source_pixels[i]));
835
0
      if (!MagickChannelEnabled(channels,BlackChannel))
836
0
        for (i=0 ; i < npixels; i++)
837
0
          SetBlackSample(&update_pixels[i],GetBlackSample(&source_pixels[i]));
838
0
      if ((update_image->matte) &&
839
0
          (!MagickChannelEnabled(channels,OpacityChannel)) &&
840
0
          (source_indexes != (const IndexPacket *) NULL) &&
841
0
          (update_indexes != (IndexPacket *) NULL))
842
0
        (void) memcpy(update_indexes,source_indexes,npixels*sizeof(IndexPacket));
843
0
    }
844
0
  else
845
0
    {
846
0
      if (!MagickChannelEnabled(channels,RedChannel))
847
0
        for (i=0 ; i < npixels; i++)
848
0
          SetRedSample(&update_pixels[i],GetRedSample(&source_pixels[i]));
849
0
      if (!MagickChannelEnabled(channels,GreenChannel))
850
0
        for (i=0 ; i < npixels; i++)
851
0
          SetGreenSample(&update_pixels[i],GetGreenSample(&source_pixels[i]));
852
0
      if (!MagickChannelEnabled(channels,BlueChannel))
853
0
        for (i=0 ; i < npixels; i++)
854
0
          SetBlueSample(&update_pixels[i],GetBlueSample(&source_pixels[i]));
855
0
      if (!MagickChannelEnabled(channels,OpacityChannel))
856
0
        for (i=0 ; i < npixels; i++)
857
0
          SetOpacitySample(&update_pixels[i],GetOpacitySample(&source_pixels[i]));
858
0
    }
859
860
0
  return MagickPass;
861
0
}
862
863
0
#define ImportImageChannelsMaskedText  "[%s] Importing channels...  "
864
MagickPassFail ImportImageChannelsMasked(const Image *source_image,
865
                                         Image *update_image,
866
                                         const ChannelType channels)
867
0
{
868
0
  ChannelType
869
0
    channel_type = channels;
870
871
0
  MagickPassFail
872
0
    status=MagickPass;
873
874
0
  assert(update_image != (Image *) NULL);
875
0
  assert(update_image->signature == MagickSignature);
876
0
  assert(source_image != (Image *) NULL);
877
0
  assert(source_image->signature == MagickSignature);
878
879
0
  if (!((AllChannels == channel_type) || (GrayChannel == channel_type)))
880
0
    {
881
0
      update_image->storage_class=DirectClass;
882
0
      status=PixelIterateDualModify(ImportImageChannelsMaskedPixels,
883
0
                                    NULL,
884
0
                                    ImportImageChannelsMaskedText,
885
0
                                    NULL,&channel_type,
886
0
                                    source_image->columns,source_image->rows,
887
0
                                    source_image,0,0,
888
0
                                    update_image,0,0,
889
0
                                    &update_image->exception);
890
0
    }
891
0
  return(status);
892
0
}
893

894
/*
895
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
896
%                                                                             %
897
%                                                                             %
898
%                                                                             %
899
%   S e t I m a g e C h a n n e l D e p t h                                   %
900
%                                                                             %
901
%                                                                             %
902
%                                                                             %
903
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
904
%
905
%  SetImageChannelDepth() translates the pixel quantums in the specified
906
%  channel so that if they are later divided to fit within the specified bit
907
%  depth, that no additional information is lost (i.e. no remainder resulting
908
%  from the division). Note that any subsequent image processing is likely
909
%  to increase the effective depth of the image channels. A non-zero
910
%  value is returned if the operation is successful. Check the exception
911
%  member of image to determine the cause for any failure.
912
%
913
%  The format of the SetImageChannelDepth method is:
914
%
915
%      MagickPassFail SetImageChannelDepth(Image *image,
916
%                                          const ChannelType channel,
917
%                                          const unsigned int depth)
918
%
919
%  A description of each parameter follows:
920
%
921
%    o image: The image to update.
922
%
923
%    o channel: Channel to modify.
924
%
925
%    o depth: Desired channel depth (range 1 to QuantumDepth)
926
%
927
%
928
*/
929
MagickExport MagickPassFail SetImageChannelDepth(Image *image,
930
                                                 const ChannelType channel,
931
                                                 const unsigned int depth)
932
0
{
933
0
  return QuantumOperatorImage(image,channel,DepthQuantumOp,(double) depth,
934
0
                              &image->exception);
935
0
}