Coverage Report

Created: 2026-06-07 07:20

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/imagemagick/MagickCore/channel.c
Line
Count
Source
1
/*
2
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3
%                                                                             %
4
%                                                                             %
5
%                                                                             %
6
%               CCCC  H   H   AAA   N   N  N   N  EEEEE   L                   %
7
%              C      H   H  A   A  NN  N  NN  N  E       L                   %
8
%              C      HHHHH  AAAAA  N N N  N N N  EEE     L                   %
9
%              C      H   H  A   A  N  NN  N  NN  E       L                   %
10
%               CCCC  H   H  A   A  N   N  N   N  EEEEE   LLLLL               %
11
%                                                                             %
12
%                                                                             %
13
%                      MagickCore Image Channel Methods                       %
14
%                                                                             %
15
%                              Software Design                                %
16
%                                   Cristy                                    %
17
%                               December 2003                                 %
18
%                                                                             %
19
%                                                                             %
20
%  Copyright @ 1999 ImageMagick Studio LLC, a non-profit organization         %
21
%  dedicated to making software imaging solutions freely available.           %
22
%                                                                             %
23
%  You may not use this file except in compliance with the License.  You may  %
24
%  obtain a copy of the License at                                            %
25
%                                                                             %
26
%    https://imagemagick.org/license/                                         %
27
%                                                                             %
28
%  Unless required by applicable law or agreed to in writing, software        %
29
%  distributed under the License is distributed on an "AS IS" BASIS,          %
30
%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
31
%  See the License for the specific language governing permissions and        %
32
%  limitations under the License.                                             %
33
%                                                                             %
34
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35
%
36
%
37
%
38
*/
39
40
/*
41
  Include declarations.
42
*/
43
#include "MagickCore/studio.h"
44
#include "MagickCore/cache-private.h"
45
#include "MagickCore/channel.h"
46
#include "MagickCore/colorspace-private.h"
47
#include "MagickCore/composite-private.h"
48
#include "MagickCore/enhance.h"
49
#include "MagickCore/image.h"
50
#include "MagickCore/list.h"
51
#include "MagickCore/log.h"
52
#include "MagickCore/monitor.h"
53
#include "MagickCore/monitor-private.h"
54
#include "MagickCore/option.h"
55
#include "MagickCore/pixel-accessor.h"
56
#include "MagickCore/resource_.h"
57
#include "MagickCore/string-private.h"
58
#include "MagickCore/thread-private.h"
59
#include "MagickCore/token.h"
60
#include "MagickCore/utility.h"
61
#include "MagickCore/version.h"
62

63
/*
64
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
65
%                                                                             %
66
%                                                                             %
67
%                                                                             %
68
%     C h a n n e l F x I m a g e                                             %
69
%                                                                             %
70
%                                                                             %
71
%                                                                             %
72
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
73
%
74
%  ChannelFxImage() applies a channel expression to the specified image.  The
75
%  expression consists of one or more channels, either mnemonic or numeric (e.g.
76
%  r, red, 0), separated by actions as follows:
77
%
78
%    <=>     exchange two channels (e.g. red<=>blue)
79
%    =>      copy one channel to another channel (e.g. red=>green)
80
%    =       assign a constant value to a channel (e.g. red=50%)
81
%    ,       write new image channels in the specified order (e.g. red, green)
82
%    ;       add a new output image for the next set of channel operations
83
%    |       move to the next input image for the source of channel data
84
%             If there are no more images in the list, | has no effect.
85
%
86
%  For example, to create 3 grayscale images from the red, green, and blue
87
%  channels of an image, use:
88
%
89
%    -channel-fx "red; green; blue"
90
%
91
%  A channel without an operation symbol implies separate (i.e, semicolon).
92
%
93
%  The format of the ChannelFxImage method is:
94
%
95
%      Image *ChannelFxImage(const Image *image,const char *expression,
96
%        ExceptionInfo *exception)
97
%
98
%  A description of each parameter follows:
99
%
100
%    o image: the image.
101
%
102
%    o expression: A channel expression.
103
%
104
%    o exception: return any errors or warnings in this structure.
105
%
106
*/
107
108
typedef enum
109
{
110
  ExtractChannelOp,
111
  AssignChannelOp,
112
  ExchangeChannelOp,
113
  TransferChannelOp
114
} ChannelFx;
115
116
static MagickBooleanType ChannelImage(Image *destination_image,
117
  const PixelChannel destination_channel,const ChannelFx channel_op,
118
  const Image *source_image,const PixelChannel source_channel,
119
  const Quantum pixel,ExceptionInfo *exception)
120
0
{
121
0
  CacheView
122
0
    *source_view,
123
0
    *destination_view;
124
125
0
  MagickBooleanType
126
0
    status = MagickTrue;
127
128
0
  size_t
129
0
    height,
130
0
    width;
131
132
0
  ssize_t
133
0
    y;
134
135
  /*
136
    Copy source channel to destination.
137
  */
138
0
  height=MagickMin(source_image->rows,destination_image->rows);
139
0
  width=MagickMin(source_image->columns,destination_image->columns);
140
0
  source_view=AcquireVirtualCacheView(source_image,exception);
141
0
  destination_view=AcquireAuthenticCacheView(destination_image,exception);
142
#if defined(MAGICKCORE_OPENMP_SUPPORT)
143
  #pragma omp parallel for schedule(static) shared(status) \
144
    magick_number_threads(source_image,source_image,height,4)
145
#endif
146
0
  for (y=0; y < (ssize_t) height; y++)
147
0
  {
148
0
    PixelTrait
149
0
      destination_traits,
150
0
      source_traits;
151
152
0
    const Quantum
153
0
      *magick_restrict p;
154
155
0
    Quantum
156
0
      *magick_restrict q;
157
158
0
    ssize_t
159
0
      x;
160
161
0
    if (status == MagickFalse)
162
0
      continue;
163
0
    p=GetCacheViewVirtualPixels(source_view,0,y,source_image->columns,1,
164
0
      exception);
165
0
    q=GetCacheViewAuthenticPixels(destination_view,0,y,
166
0
      destination_image->columns,1,exception);
167
0
    if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
168
0
      {
169
0
        status=MagickFalse;
170
0
        continue;
171
0
      }
172
0
    destination_traits=GetPixelChannelTraits(destination_image,
173
0
      destination_channel);
174
0
    source_traits=GetPixelChannelTraits(source_image,source_channel);
175
0
    if ((destination_traits == UndefinedPixelTrait) ||
176
0
        (source_traits == UndefinedPixelTrait))
177
0
      continue;
178
0
    for (x=0; x < (ssize_t) width; x++)
179
0
    {
180
0
      if (channel_op == AssignChannelOp)
181
0
        SetPixelChannel(destination_image,destination_channel,pixel,q);
182
0
      else
183
0
        SetPixelChannel(destination_image,destination_channel,
184
0
          GetPixelChannel(source_image,source_channel,p),q);
185
0
      p+=(ptrdiff_t) GetPixelChannels(source_image);
186
0
      q+=(ptrdiff_t) GetPixelChannels(destination_image);
187
0
    }
188
0
    if (SyncCacheViewAuthenticPixels(destination_view,exception) == MagickFalse)
189
0
      status=MagickFalse;
190
0
  }
191
0
  destination_view=DestroyCacheView(destination_view);
192
0
  source_view=DestroyCacheView(source_view);
193
0
  return(status);
194
0
}
195
196
MagickExport Image *ChannelFxImage(const Image *image,const char *expression,
197
  ExceptionInfo *exception)
198
0
{
199
0
#define ChannelFxImageTag  "ChannelFx/Image"
200
201
0
  ChannelFx
202
0
    channel_op = ExtractChannelOp;
203
204
0
  ChannelType
205
0
    channel_mask;
206
207
0
  char
208
0
    token[MagickPathExtent] = "";
209
210
0
  const char
211
0
    *p;
212
213
0
  const Image
214
0
    *source_image;
215
216
0
  double
217
0
    pixel = 0.0;
218
219
0
  Image
220
0
    *destination_image;
221
222
0
  MagickBooleanType
223
0
    status = MagickTrue;
224
225
0
  PixelChannel
226
0
    source_channel,
227
0
    destination_channel = RedPixelChannel;
228
229
0
  ssize_t
230
0
    channels = 0;
231
232
0
  assert(image != (Image *) NULL);
233
0
  assert(image->signature == MagickCoreSignature);
234
0
  if (IsEventLogging() != MagickFalse)
235
0
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
236
0
  assert(exception != (ExceptionInfo *) NULL);
237
0
  assert(exception->signature == MagickCoreSignature);
238
0
  p=expression;
239
0
  source_image=image;
240
0
  destination_image=CloneImage(image,0,0,MagickTrue,exception);
241
0
  if (destination_image == (Image *) NULL)
242
0
    return((Image *) NULL);
243
0
  if (expression == (const char *) NULL)
244
0
    return(destination_image);
245
0
  status=SetImageStorageClass(destination_image,DirectClass,exception);
246
0
  if (status == MagickFalse)
247
0
    {
248
0
      destination_image=GetLastImageInList(destination_image);
249
0
      return((Image *) NULL);
250
0
    }
251
0
  channel_mask=destination_image->channel_mask;
252
0
  (void) GetNextToken(p,&p,MagickPathExtent,token);
253
0
  while (*token != '\0')
254
0
  {
255
0
    PixelTrait
256
0
      traits;
257
258
0
    ssize_t
259
0
      i;
260
261
    /*
262
      Interpret channel expression.
263
    */
264
0
    switch (*token)
265
0
    {
266
0
      case ',':
267
0
      {
268
0
        (void) GetNextToken(p,&p,MagickPathExtent,token);
269
0
        break;
270
0
      }
271
0
      case '|':
272
0
      {
273
0
        if (GetNextImageInList(source_image) != (Image *) NULL)
274
0
          source_image=GetNextImageInList(source_image);
275
0
        (void) GetNextToken(p,&p,MagickPathExtent,token);
276
0
        break;
277
0
      }
278
0
      case ';':
279
0
      {
280
0
        Image
281
0
          *canvas;
282
283
0
        (void) SetPixelChannelMask(destination_image,channel_mask);
284
0
        if ((channel_op == ExtractChannelOp) && (channels == 1))
285
0
          {
286
0
            (void) SetPixelMetaChannels(destination_image,0,exception);
287
0
            (void) SetImageColorspace(destination_image,GRAYColorspace,
288
0
              exception);
289
0
          }
290
0
        canvas=CloneImage(source_image,0,0,MagickTrue,exception);
291
0
        if (canvas == (Image *) NULL)
292
0
          {
293
0
            destination_image=DestroyImageList(destination_image);
294
0
            return(destination_image);
295
0
          }
296
0
        AppendImageToList(&destination_image,canvas);
297
0
        destination_image=GetLastImageInList(destination_image);
298
0
        status=SetImageStorageClass(destination_image,DirectClass,exception);
299
0
        if (status == MagickFalse)
300
0
          {
301
0
            destination_image=GetLastImageInList(destination_image);
302
0
            return((Image *) NULL);
303
0
          }
304
0
        (void) GetNextToken(p,&p,MagickPathExtent,token);
305
0
        channels=0;
306
0
        destination_channel=RedPixelChannel;
307
0
        channel_mask=destination_image->channel_mask;
308
0
        break;
309
0
      }
310
0
      default:
311
0
        break;
312
0
    }
313
0
    i=ParsePixelChannelOption(token);
314
0
    source_channel=(PixelChannel) i;
315
0
    traits=GetPixelChannelTraits(source_image,source_channel);
316
0
    if (traits == UndefinedPixelTrait)
317
0
      {
318
0
        (void) ThrowMagickException(exception,GetMagickModule(),
319
0
          CorruptImageError,"MissingImageChannel","`%s'",token);
320
0
        destination_image=DestroyImageList(destination_image);
321
0
        return(destination_image);
322
0
      }
323
0
    channel_op=ExtractChannelOp;
324
0
    (void) GetNextToken(p,&p,MagickPathExtent,token);
325
0
    if (*token == '<')
326
0
      {
327
0
        channel_op=ExchangeChannelOp;
328
0
        (void) GetNextToken(p,&p,MagickPathExtent,token);
329
0
      }
330
0
    if (*token == '=')
331
0
      {
332
0
        if (channel_op != ExchangeChannelOp)
333
0
          channel_op=AssignChannelOp;
334
0
        (void) GetNextToken(p,&p,MagickPathExtent,token);
335
0
      }
336
0
    if (*token == '>')
337
0
      {
338
0
        if (channel_op != ExchangeChannelOp)
339
0
          channel_op=TransferChannelOp;
340
0
        (void) GetNextToken(p,&p,MagickPathExtent,token);
341
0
      }
342
0
    switch (channel_op)
343
0
    {
344
0
      case AssignChannelOp:
345
0
      case ExchangeChannelOp:
346
0
      case TransferChannelOp:
347
0
      {
348
0
        if (channel_op == AssignChannelOp)
349
0
          pixel=StringToDoubleInterval(token,(double) QuantumRange+1.0);
350
0
        else
351
0
          {
352
0
            i=ParsePixelChannelOption(token);
353
0
            if (LocaleCompare(token,"alpha") == 0)
354
0
              destination_image->alpha_trait=BlendPixelTrait;
355
0
            if (i < 0)
356
0
              {
357
0
                (void) ThrowMagickException(exception,GetMagickModule(),
358
0
                  OptionError,"UnrecognizedChannelType","`%s'",token);
359
0
                destination_image=DestroyImageList(destination_image);
360
0
                return(destination_image);
361
0
              }
362
0
          }
363
0
        destination_channel=(PixelChannel) i;
364
0
        if (image->colorspace != UndefinedColorspace)
365
0
          switch (destination_channel)
366
0
          {
367
0
            case RedPixelChannel:
368
0
            case GreenPixelChannel:
369
0
            case BluePixelChannel:
370
0
            case BlackPixelChannel:
371
0
            case AlphaPixelChannel:
372
0
            case IndexPixelChannel:
373
0
              break;
374
0
            case CompositeMaskPixelChannel:
375
0
            {
376
0
              destination_image->channels=(ChannelType)
377
0
                (destination_image->channels | CompositeMaskChannel);
378
0
              break;
379
0
            }
380
0
            case ReadMaskPixelChannel:
381
0
            {
382
0
              destination_image->channels=(ChannelType)
383
0
                (destination_image->channels | ReadMaskChannel);
384
0
              break;
385
0
            }
386
0
            case WriteMaskPixelChannel:
387
0
            {
388
0
              destination_image->channels=(ChannelType)
389
0
                (destination_image->channels | WriteMaskChannel);
390
0
              break;
391
0
            }
392
0
            case MetaPixelChannels:
393
0
            default:
394
0
            {
395
0
              traits=GetPixelChannelTraits(destination_image,
396
0
                destination_channel);
397
0
              if (traits != UndefinedPixelTrait)
398
0
                break;
399
0
              (void) SetPixelMetaChannels(destination_image,
400
0
                GetPixelMetaChannels(destination_image)+1,exception);
401
0
              traits=GetPixelChannelTraits(destination_image,
402
0
               destination_channel);
403
0
              if (traits == UndefinedPixelTrait)
404
0
                {
405
0
                  (void) ThrowMagickException(exception,GetMagickModule(),
406
0
                    CorruptImageError,"MissingImageChannel","`%s'",token);
407
0
                  destination_image=DestroyImageList(destination_image);
408
0
                  return(destination_image);
409
0
                }
410
0
              break;
411
0
            }
412
0
          }
413
0
        channel_mask=(ChannelType) (channel_mask |
414
0
          (MagickLLConstant(1) << ParseChannelOption(token)));
415
0
        (void) GetNextToken(p,&p,MagickPathExtent,token);
416
0
        break;
417
0
      }
418
0
      default:
419
0
        break;
420
0
    }
421
0
    status=ChannelImage(destination_image,destination_channel,channel_op,
422
0
      source_image,source_channel,ClampToQuantum(pixel),exception);
423
0
    if (status == MagickFalse)
424
0
      {
425
0
        destination_image=DestroyImageList(destination_image);
426
0
        break;
427
0
      }
428
0
    channels++;
429
0
    if (channel_op == ExchangeChannelOp)
430
0
      {
431
0
        status=ChannelImage(destination_image,source_channel,channel_op,
432
0
          source_image,destination_channel,ClampToQuantum(pixel),exception);
433
0
        if (status == MagickFalse)
434
0
          {
435
0
            destination_image=DestroyImageList(destination_image);
436
0
            break;
437
0
          }
438
0
        channels++;
439
0
      }
440
0
    switch (channel_op)
441
0
    {
442
0
      case ExtractChannelOp:
443
0
      {
444
0
        channel_mask=(ChannelType) (channel_mask |
445
0
          (MagickLLConstant(1) << destination_channel));
446
0
        destination_channel=(PixelChannel) (destination_channel+1);
447
0
        break;
448
0
      }
449
0
      default:
450
0
        break;
451
0
    }
452
0
    status=SetImageProgress(source_image,ChannelFxImageTag,p-expression,
453
0
      strlen(expression));
454
0
    if (status == MagickFalse)
455
0
      break;
456
0
  }
457
0
  if (destination_image == (Image *) NULL)
458
0
    return(destination_image);
459
0
  (void) SetPixelChannelMask(destination_image,channel_mask);
460
0
  if ((channel_op == ExtractChannelOp) && (channels == 1))
461
0
    {
462
0
      (void) SetPixelMetaChannels(destination_image,0,exception);
463
0
      (void) SetImageColorspace(destination_image,GRAYColorspace,exception);
464
0
    }
465
0
  return(GetFirstImageInList(destination_image));
466
0
}
467

468
/*
469
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
470
%                                                                             %
471
%                                                                             %
472
%                                                                             %
473
%     C o m b i n e I m a g e s                                               %
474
%                                                                             %
475
%                                                                             %
476
%                                                                             %
477
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
478
%
479
%  CombineImages() combines one or more images into a single image.  The
480
%  grayscale value of the pixels of each image in the sequence is assigned in
481
%  order to the specified channels of the combined image.   The typical
482
%  ordering would be image 1 => Red, 2 => Green, 3 => Blue, etc.
483
%
484
%  The format of the CombineImages method is:
485
%
486
%      Image *CombineImages(const Image *images,const ColorspaceType colorspace,
487
%        ExceptionInfo *exception)
488
%
489
%  A description of each parameter follows:
490
%
491
%    o images: the image sequence.
492
%
493
%    o colorspace: the image colorspace.
494
%
495
%    o exception: return any errors or warnings in this structure.
496
%
497
*/
498
MagickExport Image *CombineImages(const Image *image,
499
  const ColorspaceType colorspace,ExceptionInfo *exception)
500
0
{
501
0
#define CombineImageTag  "Combine/Image"
502
503
0
  CacheView
504
0
    *combine_view;
505
506
0
  Image
507
0
    *combine_image;
508
509
0
  MagickBooleanType
510
0
    status;
511
512
0
  MagickOffsetType
513
0
    progress;
514
515
0
  size_t
516
0
    number_channels;
517
518
0
  ssize_t
519
0
    y;
520
521
  /*
522
    Ensure the image are the same size.
523
  */
524
0
  assert(image != (const Image *) NULL);
525
0
  assert(image->signature == MagickCoreSignature);
526
0
  if (IsEventLogging() != MagickFalse)
527
0
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
528
0
  assert(exception != (ExceptionInfo *) NULL);
529
0
  assert(exception->signature == MagickCoreSignature);
530
0
  combine_image=CloneImage(image,0,0,MagickTrue,exception);
531
0
  if (combine_image == (Image *) NULL)
532
0
    return((Image *) NULL);
533
0
  if (SetImageStorageClass(combine_image,DirectClass,exception) == MagickFalse)
534
0
    {
535
0
      combine_image=DestroyImage(combine_image);
536
0
      return((Image *) NULL);
537
0
    }
538
0
  if (colorspace != UndefinedColorspace)
539
0
    (void) SetImageColorspace(combine_image,colorspace,exception);
540
0
  else
541
0
    if (fabs(image->gamma-1.0) <= MagickEpsilon)
542
0
      (void) SetImageColorspace(combine_image,RGBColorspace,exception);
543
0
    else
544
0
      (void) SetImageColorspace(combine_image,sRGBColorspace,exception);
545
0
  number_channels=GetImageListLength(image);
546
0
  switch (combine_image->colorspace)
547
0
  {
548
0
    case UndefinedColorspace:
549
0
    case sRGBColorspace:
550
0
    {
551
0
      if (number_channels > 3)
552
0
        combine_image->alpha_trait=BlendPixelTrait;
553
0
      if (number_channels > 4)
554
0
        SetPixelMetaChannels(combine_image,number_channels-4,exception);
555
0
      break;
556
0
    }
557
0
    case LinearGRAYColorspace:
558
0
    case GRAYColorspace:
559
0
    {
560
0
      if (number_channels > 1)
561
0
        combine_image->alpha_trait=BlendPixelTrait;
562
0
      if (number_channels > 2)
563
0
        SetPixelMetaChannels(combine_image,number_channels-2,exception);
564
0
      break;
565
0
    }
566
0
    case CMYKColorspace:
567
0
    {
568
0
      if (number_channels > 4)
569
0
        combine_image->alpha_trait=BlendPixelTrait;
570
0
      if (number_channels > 5)
571
0
        SetPixelMetaChannels(combine_image,number_channels-5,exception);
572
0
      break;
573
0
    }
574
0
    default:
575
0
      break;
576
0
  }
577
  /*
578
    Combine images.
579
  */
580
0
  status=MagickTrue;
581
0
  progress=0;
582
0
  combine_view=AcquireAuthenticCacheView(combine_image,exception);
583
#if defined(MAGICKCORE_OPENMP_SUPPORT)
584
  #pragma omp parallel for schedule(static) shared(progress,status) \
585
    magick_number_threads(combine_image,combine_image,combine_image->rows,4)
586
#endif
587
0
  for (y=0; y < (ssize_t) combine_image->rows; y++)
588
0
  {
589
0
    CacheView
590
0
      *image_view;
591
592
0
    const Image
593
0
      *next;
594
595
0
    const Quantum
596
0
      *magick_restrict p;
597
598
0
    Quantum
599
0
      *pixels,
600
0
      *magick_restrict q;
601
602
0
    ssize_t
603
0
      i;
604
605
0
    if (status == MagickFalse)
606
0
      continue;
607
0
    pixels=GetCacheViewAuthenticPixels(combine_view,0,y,combine_image->columns,
608
0
      1,exception);
609
0
    if (pixels == (Quantum *) NULL)
610
0
      {
611
0
        status=MagickFalse;
612
0
        continue;
613
0
      }
614
0
    next=image;
615
0
    for (i=0; i < (ssize_t) GetPixelChannels(combine_image); i++)
616
0
    {
617
0
      ssize_t
618
0
        x;
619
620
0
      PixelChannel channel = GetPixelChannelChannel(combine_image,i);
621
0
      PixelTrait traits = GetPixelChannelTraits(combine_image,channel);
622
0
      if (traits == UndefinedPixelTrait)
623
0
        continue;
624
0
      if (next == (Image *) NULL)
625
0
        continue;
626
0
      image_view=AcquireVirtualCacheView(next,exception);
627
0
      p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
628
0
      if (p == (const Quantum *) NULL)
629
0
        continue;
630
0
      q=pixels;
631
0
      for (x=0; x < (ssize_t) combine_image->columns; x++)
632
0
      {
633
0
        if (x < (ssize_t) next->columns)
634
0
          {
635
0
            q[i]=(Quantum) GetPixelIntensity(next,p);
636
0
            p+=(ptrdiff_t) GetPixelChannels(next);
637
0
          }
638
0
        q+=(ptrdiff_t) GetPixelChannels(combine_image);
639
0
      }
640
0
      image_view=DestroyCacheView(image_view);
641
0
      next=GetNextImageInList(next);
642
0
    }
643
0
    if (SyncCacheViewAuthenticPixels(combine_view,exception) == MagickFalse)
644
0
      status=MagickFalse;
645
0
    if (image->progress_monitor != (MagickProgressMonitor) NULL)
646
0
      {
647
0
        MagickBooleanType
648
0
          proceed;
649
650
#if defined(MAGICKCORE_OPENMP_SUPPORT)
651
        #pragma omp atomic
652
#endif
653
0
        progress++;
654
0
        proceed=SetImageProgress(image,CombineImageTag,progress,
655
0
          combine_image->rows);
656
0
        if (proceed == MagickFalse)
657
0
          status=MagickFalse;
658
0
      }
659
0
  }
660
0
  combine_view=DestroyCacheView(combine_view);
661
0
  if (status == MagickFalse)
662
0
    combine_image=DestroyImage(combine_image);
663
0
  else
664
0
    combine_image->type=UndefinedType;
665
0
  return(combine_image);
666
0
}
667

668
/*
669
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
670
%                                                                             %
671
%                                                                             %
672
%                                                                             %
673
%   G e t I m a g e A l p h a C h a n n e l                                   %
674
%                                                                             %
675
%                                                                             %
676
%                                                                             %
677
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
678
%
679
%  GetImageAlphaChannel() returns MagickFalse if the image alpha channel is
680
%  not activated.  That is, the image is RGB rather than RGBA or CMYK rather
681
%  than CMYKA.
682
%
683
%  The format of the GetImageAlphaChannel method is:
684
%
685
%      MagickBooleanType GetImageAlphaChannel(const Image *image)
686
%
687
%  A description of each parameter follows:
688
%
689
%    o image: the image.
690
%
691
*/
692
MagickExport MagickBooleanType GetImageAlphaChannel(const Image *image)
693
0
{
694
0
  assert(image != (const Image *) NULL);
695
0
  if (IsEventLogging() != MagickFalse)
696
0
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
697
0
  assert(image->signature == MagickCoreSignature);
698
0
  return(image->alpha_trait != UndefinedPixelTrait ? MagickTrue : MagickFalse);
699
0
}
700

701
/*
702
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
703
%                                                                             %
704
%                                                                             %
705
%                                                                             %
706
%     S e p a r a t e I m a g e                                               %
707
%                                                                             %
708
%                                                                             %
709
%                                                                             %
710
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
711
%
712
%  SeparateImage() separates a channel from the image and returns it as a
713
%  grayscale image.
714
%
715
%  The format of the SeparateImage method is:
716
%
717
%      Image *SeparateImage(const Image *image,const ChannelType channel,
718
%        ExceptionInfo *exception)
719
%
720
%  A description of each parameter follows:
721
%
722
%    o image: the image.
723
%
724
%    o channel: the image channel.
725
%
726
%    o exception: return any errors or warnings in this structure.
727
%
728
*/
729
MagickExport Image *SeparateImage(const Image *image,
730
  const ChannelType channel_type,ExceptionInfo *exception)
731
351k
{
732
1.72G
#define GetChannelBit(mask,bit)  (((size_t) (mask) >> (size_t) (bit)) & 0x01)
733
351k
#define SeparateImageTag  "Separate/Image"
734
735
351k
  CacheView
736
351k
    *image_view,
737
351k
    *separate_view;
738
739
351k
  Image
740
351k
    *separate_image;
741
742
351k
  MagickBooleanType
743
351k
    status;
744
745
351k
  MagickOffsetType
746
351k
    progress;
747
748
351k
  ssize_t
749
351k
    y;
750
751
  /*
752
    Initialize separate image attributes.
753
  */
754
351k
  assert(image != (Image *) NULL);
755
351k
  assert(image->signature == MagickCoreSignature);
756
351k
  if (IsEventLogging() != MagickFalse)
757
0
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
758
351k
  assert(exception != (ExceptionInfo *) NULL);
759
351k
  assert(exception->signature == MagickCoreSignature);
760
351k
  separate_image=CloneImage(image,0,0,MagickTrue,exception);
761
351k
  if (separate_image == (Image *) NULL)
762
0
    return((Image *) NULL);
763
351k
  if (SetImageStorageClass(separate_image,DirectClass,exception) == MagickFalse)
764
0
    {
765
0
      separate_image=DestroyImage(separate_image);
766
0
      return((Image *) NULL);
767
0
    }
768
351k
  separate_image->alpha_trait=UndefinedPixelTrait;
769
351k
  (void) SetImageColorspace(separate_image,GRAYColorspace,exception);
770
351k
  separate_image->gamma=image->gamma;
771
  /*
772
    Separate image.
773
  */
774
351k
  status=MagickTrue;
775
351k
  progress=0;
776
351k
  image_view=AcquireVirtualCacheView(image,exception);
777
351k
  separate_view=AcquireAuthenticCacheView(separate_image,exception);
778
#if defined(MAGICKCORE_OPENMP_SUPPORT)
779
  #pragma omp parallel for schedule(static) shared(progress,status) \
780
    magick_number_threads(image,image,image->rows,2)
781
#endif
782
9.23M
  for (y=0; y < (ssize_t) image->rows; y++)
783
8.88M
  {
784
8.88M
    const Quantum
785
8.88M
      *magick_restrict p;
786
787
8.88M
    Quantum
788
8.88M
      *magick_restrict q;
789
790
8.88M
    ssize_t
791
8.88M
      x;
792
793
8.88M
    if (status == MagickFalse)
794
0
      continue;
795
8.88M
    p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
796
8.88M
    q=QueueCacheViewAuthenticPixels(separate_view,0,y,separate_image->columns,1,
797
8.88M
      exception);
798
8.88M
    if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
799
0
      {
800
0
        status=MagickFalse;
801
0
        continue;
802
0
      }
803
393M
    for (x=0; x < (ssize_t) image->columns; x++)
804
384M
    {
805
384M
      ssize_t
806
384M
        i;
807
808
384M
      SetPixelChannel(separate_image,GrayPixelChannel,(Quantum) 0,q);
809
2.11G
      for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
810
1.72G
      {
811
1.72G
        PixelChannel channel = GetPixelChannelChannel(image,i);
812
1.72G
        PixelTrait traits = GetPixelChannelTraits(image,channel);
813
1.72G
        if ((traits == UndefinedPixelTrait) ||
814
1.72G
            (GetChannelBit(channel_type,channel) == 0))
815
1.34G
          continue;
816
384M
        SetPixelChannel(separate_image,GrayPixelChannel,p[i],q);
817
384M
      }
818
384M
      p+=(ptrdiff_t) GetPixelChannels(image);
819
384M
      q+=(ptrdiff_t) GetPixelChannels(separate_image);
820
384M
    }
821
8.88M
    if (SyncCacheViewAuthenticPixels(separate_view,exception) == MagickFalse)
822
0
      status=MagickFalse;
823
8.88M
    if (image->progress_monitor != (MagickProgressMonitor) NULL)
824
0
      {
825
0
        MagickBooleanType
826
0
          proceed;
827
828
#if defined(MAGICKCORE_OPENMP_SUPPORT)
829
        #pragma omp atomic
830
#endif
831
0
        progress++;
832
0
        proceed=SetImageProgress(image,SeparateImageTag,progress,image->rows);
833
0
        if (proceed == MagickFalse)
834
0
          status=MagickFalse;
835
0
      }
836
8.88M
  }
837
351k
  separate_view=DestroyCacheView(separate_view);
838
351k
  image_view=DestroyCacheView(image_view);
839
351k
  (void) SetImageChannelMask(separate_image,AllChannels);
840
351k
  if (status == MagickFalse)
841
0
    separate_image=DestroyImage(separate_image);
842
351k
  return(separate_image);
843
351k
}
844

845
/*
846
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
847
%                                                                             %
848
%                                                                             %
849
%                                                                             %
850
%     S e p a r a t e I m a g e s                                             %
851
%                                                                             %
852
%                                                                             %
853
%                                                                             %
854
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
855
%
856
%  SeparateImages() returns a separate grayscale image for each channel
857
%  specified.
858
%
859
%  The format of the SeparateImages method is:
860
%
861
%      Image *SeparateImages(const Image *image,ExceptionInfo *exception)
862
%
863
%  A description of each parameter follows:
864
%
865
%    o image: the image.
866
%
867
%    o exception: return any errors or warnings in this structure.
868
%
869
*/
870
MagickExport Image *SeparateImages(const Image *image,ExceptionInfo *exception)
871
0
{
872
0
  Image
873
0
    *images,
874
0
    *separate_image;
875
876
0
  ssize_t
877
0
    i;
878
879
0
  assert(image != (Image *) NULL);
880
0
  assert(image->signature == MagickCoreSignature);
881
0
  if (IsEventLogging() != MagickFalse)
882
0
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
883
0
  images=NewImageList();
884
0
  for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
885
0
  {
886
0
    PixelChannel channel = GetPixelChannelChannel(image,i);
887
0
    PixelTrait traits = GetPixelChannelTraits(image,channel);
888
0
    if ((traits == UndefinedPixelTrait) || ((traits & UpdatePixelTrait) == 0))
889
0
      continue;
890
0
    separate_image=SeparateImage(image,(ChannelType)
891
0
      (MagickLLConstant(1) << channel),exception);
892
0
    if (separate_image != (Image *) NULL)
893
0
      AppendImageToList(&images,separate_image);
894
0
  }
895
0
  if (images == (Image *) NULL)
896
0
    images=SeparateImage(image,UndefinedChannel,exception);
897
0
  return(images);
898
0
}
899

900
/*
901
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
902
%                                                                             %
903
%                                                                             %
904
%                                                                             %
905
%   S e t I m a g e A l p h a C h a n n e l                                   %
906
%                                                                             %
907
%                                                                             %
908
%                                                                             %
909
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
910
%
911
%  SetImageAlphaChannel() activates, deactivates, resets, or sets the alpha
912
%  channel.
913
%
914
%  The format of the SetImageAlphaChannel method is:
915
%
916
%      MagickBooleanType SetImageAlphaChannel(Image *image,
917
%        const AlphaChannelOption alpha_type,ExceptionInfo *exception)
918
%
919
%  A description of each parameter follows:
920
%
921
%    o image: the image.
922
%
923
%    o alpha_type:  The alpha channel type: ActivateAlphaChannel,
924
%      AssociateAlphaChannel, CopyAlphaChannel, DeactivateAlphaChannel,
925
%      DisassociateAlphaChannel,  ExtractAlphaChannel, OffAlphaChannel,
926
%      OnAlphaChannel, OpaqueAlphaChannel, SetAlphaChannel, ShapeAlphaChannel,
927
%      and TransparentAlphaChannel.
928
%
929
%    o exception: return any errors or warnings in this structure.
930
%
931
*/
932
933
static inline void FlattenPixelInfo(const Image *image,const PixelInfo *p,
934
  const double alpha,const Quantum *q,const double beta,Quantum *composite)
935
0
{
936
0
  double
937
0
    Da,
938
0
    gamma,
939
0
    Sa;
940
941
0
  ssize_t
942
0
    i;
943
944
  /*
945
    Compose pixel p over pixel q with the given alpha.
946
  */
947
0
  Sa=QuantumScale*alpha;
948
0
  Da=QuantumScale*beta,
949
0
  gamma=Sa*(-Da)+Sa+Da;
950
0
  gamma=MagickSafeReciprocal(gamma);
951
0
  for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
952
0
  {
953
0
    PixelChannel channel = GetPixelChannelChannel(image,i);
954
0
    PixelTrait traits = GetPixelChannelTraits(image,channel);
955
0
    if (traits == UndefinedPixelTrait)
956
0
      continue;
957
0
    switch (channel)
958
0
    {
959
0
      case RedPixelChannel:
960
0
      {
961
0
        composite[i]=ClampToQuantum(gamma*MagickOver_((double) q[i],beta,
962
0
          (double) p->red,alpha));
963
0
        break;
964
0
      }
965
0
      case GreenPixelChannel:
966
0
      {
967
0
        composite[i]=ClampToQuantum(gamma*MagickOver_((double) q[i],beta,
968
0
          (double) p->green,alpha));
969
0
        break;
970
0
      }
971
0
      case BluePixelChannel:
972
0
      {
973
0
        composite[i]=ClampToQuantum(gamma*MagickOver_((double) q[i],beta,
974
0
          (double) p->blue,alpha));
975
0
        break;
976
0
      }
977
0
      case BlackPixelChannel:
978
0
      {
979
0
        composite[i]=ClampToQuantum(gamma*MagickOver_((double) q[i],beta,
980
0
          (double) p->black,alpha));
981
0
        break;
982
0
      }
983
0
      case AlphaPixelChannel:
984
0
      {
985
0
        composite[i]=ClampToQuantum((double) QuantumRange*(Sa*(-Da)+Sa+Da));
986
0
        break;
987
0
      }
988
0
      default:
989
0
        break;
990
0
    }
991
0
  }
992
0
}
993
994
MagickExport MagickBooleanType SetImageAlphaChannel(Image *image,
995
  const AlphaChannelOption alpha_type,ExceptionInfo *exception)
996
383k
{
997
383k
  CacheView
998
383k
    *image_view;
999
1000
383k
  MagickBooleanType
1001
383k
    status;
1002
1003
383k
  ssize_t
1004
383k
    y;
1005
1006
383k
  assert(image != (Image *) NULL);
1007
383k
  if (IsEventLogging() != MagickFalse)
1008
0
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1009
383k
  assert(image->signature == MagickCoreSignature);
1010
383k
  status=MagickTrue;
1011
383k
  switch (alpha_type)
1012
383k
  {
1013
362k
    case ActivateAlphaChannel:
1014
362k
    {
1015
362k
      if ((image->alpha_trait & BlendPixelTrait) != 0)
1016
0
        return(status);
1017
362k
      image->alpha_trait=BlendPixelTrait;
1018
362k
      break;
1019
362k
    }
1020
0
    case AssociateAlphaChannel:
1021
0
    {
1022
      /*
1023
        Associate alpha.
1024
      */
1025
0
      status=SetImageStorageClass(image,DirectClass,exception);
1026
0
      if (status == MagickFalse)
1027
0
        break;
1028
0
      image_view=AcquireAuthenticCacheView(image,exception);
1029
#if defined(MAGICKCORE_OPENMP_SUPPORT)
1030
      #pragma omp parallel for schedule(static) shared(status) \
1031
        magick_number_threads(image,image,image->rows,2)
1032
#endif
1033
0
      for (y=0; y < (ssize_t) image->rows; y++)
1034
0
      {
1035
0
        Quantum
1036
0
          *magick_restrict q;
1037
1038
0
        ssize_t
1039
0
          x;
1040
1041
0
        if (status == MagickFalse)
1042
0
          continue;
1043
0
        q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
1044
0
          exception);
1045
0
        if (q == (Quantum *) NULL)
1046
0
          {
1047
0
            status=MagickFalse;
1048
0
            continue;
1049
0
          }
1050
0
        for (x=0; x < (ssize_t) image->columns; x++)
1051
0
        {
1052
0
          double
1053
0
            gamma;
1054
1055
0
          ssize_t
1056
0
            i;
1057
1058
0
          gamma=QuantumScale*(double) GetPixelAlpha(image,q);
1059
0
          for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1060
0
          {
1061
0
            PixelChannel channel = GetPixelChannelChannel(image,i);
1062
0
            PixelTrait traits = GetPixelChannelTraits(image,channel);
1063
0
            if (channel == AlphaPixelChannel)
1064
0
              continue;
1065
0
            if ((traits & UpdatePixelTrait) == 0)
1066
0
              continue;
1067
0
            q[i]=ClampToQuantum(gamma*(double) q[i]);
1068
0
          }
1069
0
          q+=(ptrdiff_t) GetPixelChannels(image);
1070
0
        }
1071
0
        if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
1072
0
          status=MagickFalse;
1073
0
      }
1074
0
      image_view=DestroyCacheView(image_view);
1075
0
      image->alpha_trait=CopyPixelTrait;
1076
0
      return(status);
1077
0
    }
1078
0
    case BackgroundAlphaChannel:
1079
0
    {
1080
      /*
1081
        Set transparent pixels to background color.
1082
      */
1083
0
      if ((image->alpha_trait & BlendPixelTrait) == 0)
1084
0
        break;
1085
0
      status=SetImageStorageClass(image,DirectClass,exception);
1086
0
      if (status == MagickFalse)
1087
0
        break;
1088
0
      image_view=AcquireAuthenticCacheView(image,exception);
1089
#if defined(MAGICKCORE_OPENMP_SUPPORT)
1090
      #pragma omp parallel for schedule(static) shared(status) \
1091
        magick_number_threads(image,image,image->rows,2)
1092
#endif
1093
0
      for (y=0; y < (ssize_t) image->rows; y++)
1094
0
      {
1095
0
        Quantum
1096
0
          *magick_restrict q;
1097
1098
0
        ssize_t
1099
0
          x;
1100
1101
0
        if (status == MagickFalse)
1102
0
          continue;
1103
0
        q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
1104
0
          exception);
1105
0
        if (q == (Quantum *) NULL)
1106
0
          {
1107
0
            status=MagickFalse;
1108
0
            continue;
1109
0
          }
1110
0
        for (x=0; x < (ssize_t) image->columns; x++)
1111
0
        {
1112
0
          if (GetPixelAlpha(image,q) == TransparentAlpha)
1113
0
            {
1114
0
              SetPixelViaPixelInfo(image,&image->background_color,q);
1115
0
              SetPixelChannel(image,AlphaPixelChannel,TransparentAlpha,q);
1116
0
            }
1117
0
          q+=(ptrdiff_t) GetPixelChannels(image);
1118
0
        }
1119
0
        if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
1120
0
          status=MagickFalse;
1121
0
      }
1122
0
      image_view=DestroyCacheView(image_view);
1123
0
      return(status);
1124
0
    }
1125
0
    case CopyAlphaChannel:
1126
0
    {
1127
0
      image->alpha_trait=UpdatePixelTrait;
1128
0
      status=CompositeImage(image,image,IntensityCompositeOp,MagickTrue,0,0,
1129
0
        exception);
1130
0
      break;
1131
0
    }
1132
0
    case DeactivateAlphaChannel:
1133
0
    {
1134
0
      if ((image->alpha_trait & BlendPixelTrait) == 0)
1135
0
        status=SetImageAlpha(image,OpaqueAlpha,exception);
1136
0
      image->alpha_trait=CopyPixelTrait;
1137
0
      break;
1138
0
    }
1139
0
    case DisassociateAlphaChannel:
1140
0
    {
1141
      /*
1142
        Disassociate alpha.
1143
      */
1144
0
      status=SetImageStorageClass(image,DirectClass,exception);
1145
0
      if (status == MagickFalse)
1146
0
        break;
1147
0
      image->alpha_trait=BlendPixelTrait;
1148
0
      image_view=AcquireAuthenticCacheView(image,exception);
1149
#if defined(MAGICKCORE_OPENMP_SUPPORT)
1150
      #pragma omp parallel for schedule(static) shared(status) \
1151
        magick_number_threads(image,image,image->rows,2)
1152
#endif
1153
0
      for (y=0; y < (ssize_t) image->rows; y++)
1154
0
      {
1155
0
        Quantum
1156
0
          *magick_restrict q;
1157
1158
0
        ssize_t
1159
0
          x;
1160
1161
0
        if (status == MagickFalse)
1162
0
          continue;
1163
0
        q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
1164
0
          exception);
1165
0
        if (q == (Quantum *) NULL)
1166
0
          {
1167
0
            status=MagickFalse;
1168
0
            continue;
1169
0
          }
1170
0
        for (x=0; x < (ssize_t) image->columns; x++)
1171
0
        {
1172
0
          double
1173
0
            gamma,
1174
0
            Sa;
1175
1176
0
          ssize_t
1177
0
            i;
1178
1179
0
          Sa=QuantumScale*(double) GetPixelAlpha(image,q);
1180
0
          gamma=MagickSafeReciprocal(Sa);
1181
0
          for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1182
0
          {
1183
0
            PixelChannel channel = GetPixelChannelChannel(image,i);
1184
0
            PixelTrait traits = GetPixelChannelTraits(image,channel);
1185
0
            if (channel == AlphaPixelChannel)
1186
0
              continue;
1187
0
            if ((traits & UpdatePixelTrait) == 0)
1188
0
              continue;
1189
0
            q[i]=ClampToQuantum(gamma*(double) q[i]);
1190
0
          }
1191
0
          q+=(ptrdiff_t) GetPixelChannels(image);
1192
0
        }
1193
0
        if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
1194
0
          status=MagickFalse;
1195
0
      }
1196
0
      image_view=DestroyCacheView(image_view);
1197
0
      image->alpha_trait=UndefinedPixelTrait;
1198
0
      return(status);
1199
0
    }
1200
0
    case DiscreteAlphaChannel:
1201
0
    {
1202
0
      if ((image->alpha_trait & BlendPixelTrait) == 0)
1203
0
        status=SetImageAlpha(image,OpaqueAlpha,exception);
1204
0
      image->alpha_trait=UpdatePixelTrait;
1205
0
      break;
1206
0
    }
1207
0
    case ExtractAlphaChannel:
1208
0
    {
1209
0
      status=CompositeImage(image,image,AlphaCompositeOp,MagickTrue,0,0,
1210
0
        exception);
1211
0
      image->alpha_trait=UndefinedPixelTrait;
1212
0
      break;
1213
0
    }
1214
0
    case OffAlphaChannel:
1215
0
    {
1216
0
      if ((image->alpha_trait & BlendPixelTrait) == 0)
1217
0
        return(status);
1218
0
      image->alpha_trait=UndefinedPixelTrait;
1219
0
      break;
1220
0
    }
1221
0
    case OffIfOpaqueAlphaChannel:
1222
0
    {
1223
0
      MagickBooleanType
1224
0
        opaque = MagickTrue;
1225
1226
      /*
1227
        Remove opaque alpha channel.
1228
      */
1229
0
      if ((image->alpha_trait & BlendPixelTrait) == 0)
1230
0
        break;
1231
0
      image_view=AcquireVirtualCacheView(image,exception);
1232
#if defined(MAGICKCORE_OPENMP_SUPPORT)
1233
      #pragma omp parallel for schedule(static) shared(opaque,status) \
1234
        magick_number_threads(image,image,image->rows,2)
1235
#endif
1236
0
      for (y=0; y < (ssize_t) image->rows; y++)
1237
0
      {
1238
0
        const Quantum
1239
0
          *magick_restrict p;
1240
1241
0
        ssize_t
1242
0
          x;
1243
1244
0
        if ((status == MagickFalse) || (opaque == MagickFalse))
1245
0
          continue;
1246
0
        p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
1247
0
        if (p == (const Quantum *) NULL)
1248
0
          {
1249
0
            status=MagickFalse;
1250
0
            continue;
1251
0
          }
1252
0
        for (x=0; x < (ssize_t) image->columns; x++)
1253
0
        {
1254
0
          if (GetPixelAlpha(image,p) != OpaqueAlpha)
1255
0
            {
1256
0
              opaque=MagickFalse;
1257
0
              break;
1258
0
            }
1259
0
          p+=(ptrdiff_t) GetPixelChannels(image);
1260
0
        }
1261
0
      }
1262
0
      image_view=DestroyCacheView(image_view);
1263
0
      if (opaque != MagickFalse)
1264
0
        image->alpha_trait=UndefinedPixelTrait;
1265
0
      break;
1266
0
    }
1267
0
    case OnAlphaChannel:
1268
0
    {
1269
0
      if ((image->alpha_trait & BlendPixelTrait) == 0)
1270
0
        status=SetImageAlpha(image,OpaqueAlpha,exception);
1271
0
      image->alpha_trait=BlendPixelTrait;
1272
0
      break;
1273
0
    }
1274
21.9k
    case OpaqueAlphaChannel:
1275
21.9k
    {
1276
21.9k
      status=SetImageAlpha(image,OpaqueAlpha,exception);
1277
21.9k
      break;
1278
0
    }
1279
0
    case RemoveAlphaChannel:
1280
0
    {
1281
      /*
1282
        Remove transparency.
1283
      */
1284
0
      if ((image->alpha_trait & BlendPixelTrait) == 0)
1285
0
        break;
1286
0
      status=SetImageStorageClass(image,DirectClass,exception);
1287
0
      if (status == MagickFalse)
1288
0
        break;
1289
0
      image_view=AcquireAuthenticCacheView(image,exception);
1290
#if defined(MAGICKCORE_OPENMP_SUPPORT)
1291
      #pragma omp parallel for schedule(static) shared(status) \
1292
        magick_number_threads(image,image,image->rows,2)
1293
#endif
1294
0
      for (y=0; y < (ssize_t) image->rows; y++)
1295
0
      {
1296
0
        Quantum
1297
0
          *magick_restrict q;
1298
1299
0
        ssize_t
1300
0
          x;
1301
1302
0
        if (status == MagickFalse)
1303
0
          continue;
1304
0
        q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
1305
0
          exception);
1306
0
        if (q == (Quantum *) NULL)
1307
0
          {
1308
0
            status=MagickFalse;
1309
0
            continue;
1310
0
          }
1311
0
        for (x=0; x < (ssize_t) image->columns; x++)
1312
0
        {
1313
0
          FlattenPixelInfo(image,&image->background_color,
1314
0
            image->background_color.alpha,q,(double) GetPixelAlpha(image,q),q);
1315
0
          q+=(ptrdiff_t) GetPixelChannels(image);
1316
0
        }
1317
0
        if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
1318
0
          status=MagickFalse;
1319
0
      }
1320
0
      image_view=DestroyCacheView(image_view);
1321
0
      image->alpha_trait=image->background_color.alpha_trait;
1322
0
      break;
1323
0
    }
1324
0
    case SetAlphaChannel:
1325
0
    {
1326
0
      if ((image->alpha_trait & BlendPixelTrait) == 0)
1327
0
        status=SetImageAlpha(image,OpaqueAlpha,exception);
1328
0
      break;
1329
0
    }
1330
0
    case ShapeAlphaChannel:
1331
0
    {
1332
0
      PixelInfo
1333
0
        background;
1334
1335
      /*
1336
        Remove transparency.
1337
      */
1338
0
      ConformPixelInfo(image,&image->background_color,&background,exception);
1339
0
      background.alpha_trait=BlendPixelTrait;
1340
0
      image->alpha_trait=BlendPixelTrait;
1341
0
      status=SetImageStorageClass(image,DirectClass,exception);
1342
0
      if (status == MagickFalse)
1343
0
        break;
1344
0
      image_view=AcquireAuthenticCacheView(image,exception);
1345
#if defined(MAGICKCORE_OPENMP_SUPPORT)
1346
      #pragma omp parallel for schedule(static) shared(status) \
1347
        magick_number_threads(image,image,image->rows,2)
1348
#endif
1349
0
      for (y=0; y < (ssize_t) image->rows; y++)
1350
0
      {
1351
0
        PixelInfo
1352
0
          pixel;
1353
1354
0
        Quantum
1355
0
          *magick_restrict q;
1356
1357
0
        ssize_t
1358
0
          x;
1359
1360
0
        if (status == MagickFalse)
1361
0
          continue;
1362
0
        q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
1363
0
          exception);
1364
0
        if (q == (Quantum *) NULL)
1365
0
          {
1366
0
            status=MagickFalse;
1367
0
            continue;
1368
0
          }
1369
0
        pixel=background;
1370
0
        for (x=0; x < (ssize_t) image->columns; x++)
1371
0
        {
1372
0
          pixel.alpha=GetPixelIntensity(image,q);
1373
0
          SetPixelViaPixelInfo(image,&pixel,q);
1374
0
          q+=(ptrdiff_t) GetPixelChannels(image);
1375
0
        }
1376
0
        if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
1377
0
          status=MagickFalse;
1378
0
      }
1379
0
      image_view=DestroyCacheView(image_view);
1380
0
      break;
1381
0
    }
1382
0
    case TransparentAlphaChannel:
1383
0
    {
1384
0
      status=SetImageAlpha(image,TransparentAlpha,exception);
1385
0
      break;
1386
0
    }
1387
0
    case UndefinedAlphaChannel:
1388
0
      break;
1389
383k
  }
1390
383k
  if (status == MagickFalse)
1391
0
    return(status);
1392
383k
  (void) SetPixelChannelMask(image,image->channel_mask);
1393
383k
  return(SyncImagePixelCache(image,exception));
1394
383k
}