Coverage Report

Created: 2025-12-31 07:53

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/graphicsmagick/magick/operator.c
Line
Count
Source
1
/*
2
% Copyright (C) 2004 - 2022 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
% Interfaces to support quantum operators.
9
% Written by Bob Friesenhahn, March 2004.
10
%
11
*/
12

13
/*
14
  Include declarations.
15
*/
16
#include "magick/studio.h"
17
#include "magick/enum_strings.h"
18
#include "magick/gem.h"
19
#include "magick/pixel_iterator.h"
20
#include "magick/random.h"
21
#include "magick/utility.h"
22
#include "magick/operator.h"
23

24
/*
25
  Types.
26
*/
27
typedef struct _QuantumImmutableContext
28
{
29
  ChannelType channel;
30
  Quantum quantum_value;
31
  double double_value;
32
} QuantumImmutableContext;
33
34
typedef struct _QuantumMutableContext
35
{
36
  Quantum *channel_lut;
37
} QuantumMutableContext;
38
39
typedef struct _ChannelOptions_t
40
{
41
  DoublePixelPacket
42
    values;
43
44
  MagickBool
45
    red_enabled,
46
    green_enabled,
47
    blue_enabled,
48
    opacity_enabled;
49
} ChannelOptions_t;
50

51
/*
52
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
53
%                                                                             %
54
%                                                                             %
55
%                                                                             %
56
%   Q u a n t u m O p e r a t o r I m a g e                                   %
57
%                                                                             %
58
%                                                                             %
59
%                                                                             %
60
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
61
%
62
%  QuantumOperatorImage() performs the requested arithmetic,
63
%  bitwise-logical, or value operation on the selected channels of
64
%  the entire image.  The AllChannels channel option operates on all
65
%  color channels whereas the GrayChannel channel option treats the
66
%  color channels as a grayscale intensity.
67
%
68
%  These operations are on the DirectClass pixels of the image and do not
69
%  update pixel indexes or colormap.
70
%
71
%  The format of the QuantumOperatorImage method is:
72
%
73
%      MagickPassFail QuantumOperatorImage(Image *image,
74
%        ChannelType channel, QuantumOperator operator,
75
%        double rvalue)
76
%
77
%  A description of each parameter follows:
78
%
79
%    o image: The image.
80
%
81
%    o channel: Channel to operate on (RedChannel, CyanChannel,
82
%        GreenChannel, MagentaChannel, BlueChannel, YellowChannel,
83
%        OpacityChannel, BlackChannel, MatteChannel, AllChannels,
84
%        GrayChannel).  The AllChannels type only updates color
85
%        channels.  The GrayChannel type treats the color channels
86
%        as if they represent an intensity.
87
%
88
%    o quantum_operator: Operator to use (AddQuantumOp, AndQuantumOp,
89
%        AssignQuantumOp, DepthQuantumOp, DivideQuantumOp, GammaQuantumOp,
90
%        LShiftQuantumOp, MultiplyQuantumOp,  NegateQuantumOp,
91
%        NoiseGaussianQuantumOp, NoiseImpulseQuantumOp,
92
%        NoiseLaplacianQuantumOp, NoiseMultiplicativeQuantumOp,
93
%        NoisePoissonQuantumOp, NoiseRandomQuantumOp, NoiseUniformQuantumOp,
94
%        OrQuantumOp, RShiftQuantumOp, SubtractQuantumOp,
95
%        ThresholdBlackQuantumOp, ThresholdQuantumOp, ThresholdWhiteQuantumOp,
96
%        ThresholdBlackNegateQuantumOp, ThresholdWhiteNegateQuantumOp,
97
%        XorQuantumOp).
98
%
99
%    o rvalue: Operator argument.
100
%
101
%    o exception: Updated with error description.
102
%
103
*/
104
MagickExport MagickPassFail QuantumOperatorImage(Image *image,
105
  const ChannelType channel,const QuantumOperator quantum_operator,
106
  const double rvalue,ExceptionInfo *exception)
107
0
{
108
0
  return QuantumOperatorRegionImage(image,0,0,image->columns,image->rows,
109
0
                                    channel,quantum_operator,rvalue,exception);
110
0
}
111

112
/*
113
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
114
%                                                                             %
115
%                                                                             %
116
%                                                                             %
117
+   Q u a n t u m O p e r a t o r I m a g e M u l t i v a l u e               %
118
%                                                                             %
119
%                                                                             %
120
%                                                                             %
121
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
122
%
123
%  QuantumOperatorImageMultivalue() is a semi-private implementation
124
%  function which accepts a comma delimited string of per-channel values
125
%  and applies a specified operator to the channels of the image.  The
126
%  main reason for this function to exist is to support
127
%  ChannelThresholdPixels(), BlackThresholdImage(), WhiteThresholdImage(),
128
%  or any other legacy style function which needs to be implemented.
129
%
130
%  The format of the QuantumOperatorImageMultivalue method is:
131
%
132
%      MagickPassFail QuantumOperatorImageMultivalue(
133
%                                 Image *image,
134
%                                 const QuantumOperator quantum_operator,
135
%                                 const char *values)
136
%
137
%  A description of each parameter follows:
138
%
139
%    o image: The image.
140
%
141
%    o values: define the rvalues, <red>{<green>,<blue>,<opacity>}{%}.
142
%
143
*/
144
MagickExport MagickPassFail
145
QuantumOperatorImageMultivalue(Image *image,
146
                               const QuantumOperator quantum_operator,
147
                               const char *values)
148
0
{
149
0
  ChannelOptions_t
150
0
    options;
151
152
0
  int
153
0
    count;
154
155
0
  MagickPassFail
156
0
    status;
157
158
0
  assert(image != (Image *) NULL);
159
0
  assert(image->signature == MagickSignature);
160
0
  if (values == (const char *) NULL)
161
0
    return MagickFail;;
162
163
0
  options.red_enabled        = MagickFalse;
164
0
  options.green_enabled      = MagickFalse;
165
0
  options.blue_enabled       = MagickFalse;
166
0
  options.opacity_enabled    = MagickFalse;
167
168
0
  options.values.red       = -1.0;
169
0
  options.values.green     = -1.0;
170
0
  options.values.blue      = -1.0;
171
0
  options.values.opacity   = -1.0;
172
0
  count=sscanf(values,"%lf%*[/,%%]%lf%*[/,%%]%lf%*[/,%%]%lf",
173
0
               &options.values.red,
174
0
               &options.values.green,
175
0
               &options.values.blue,
176
0
               &options.values.opacity);
177
178
0
  if ((count > 3) && (options.values.opacity >= 0.0))
179
0
    options.opacity_enabled = MagickTrue;
180
0
  if ((count > 2) && (options.values.blue >= 0.0))
181
0
    options.blue_enabled = MagickTrue;
182
0
  if ((count > 1) && (options.values.green >= 0.0))
183
0
    options.green_enabled = MagickTrue;
184
0
  if ((count > 0) && (options.values.red >= 0.0))
185
0
    options.red_enabled = MagickTrue;
186
187
0
  if (strchr(values,'%') != (char *) NULL)
188
0
    {
189
0
      if (options.red_enabled)
190
0
        options.values.red     *= MaxRGB/100.0;
191
0
      if (options.green_enabled)
192
0
        options.values.green   *= MaxRGB/100.0;
193
0
      if (options.blue_enabled)
194
0
        options.values.blue    *= MaxRGB/100.0;
195
0
      if (options.opacity_enabled)
196
0
        options.values.opacity *= MaxRGB/100.0;
197
0
    }
198
199
0
  status=MagickPass;
200
201
0
  if ((IsRGBColorspace(image->colorspace)) &&
202
0
      ((count == 1) ||
203
0
       ((options.values.red == options.values.green) &&
204
0
        (options.values.green == options.values.blue))))
205
0
    {
206
      /*
207
        Apply operation to all channels in gray or RGB space.
208
      */
209
0
      if (IsGrayColorspace(image->colorspace))
210
0
        status=QuantumOperatorImage(image,GrayChannel,quantum_operator,
211
0
                                    options.values.red,&image->exception);
212
0
      else
213
0
        status=QuantumOperatorImage(image,AllChannels,quantum_operator,
214
0
                                    options.values.red,&image->exception);
215
0
    }
216
0
  else
217
0
    {
218
      /*
219
        Apply operator to individual RGB(A) channels.
220
      */
221
0
      if ((MagickPass == status) && (options.red_enabled))
222
0
        {
223
0
          status=QuantumOperatorImage(image,RedChannel,quantum_operator,
224
0
                                      options.values.red,&image->exception);
225
0
        }
226
227
0
      if ((MagickPass == status) && (options.green_enabled))
228
0
        {
229
0
          status=QuantumOperatorImage(image,GreenChannel,quantum_operator,
230
0
                                      options.values.green,&image->exception);
231
0
        }
232
233
0
      if ((MagickPass == status) && (options.blue_enabled))
234
0
        {
235
0
          status=QuantumOperatorImage(image,BlueChannel,quantum_operator,
236
0
                                      options.values.blue,&image->exception);
237
0
        }
238
239
0
      if ((MagickPass == status) && (options.opacity_enabled))
240
0
        {
241
0
          status=QuantumOperatorImage(image,OpacityChannel,quantum_operator,
242
0
                                      options.values.opacity,&image->exception);
243
0
        }
244
0
    }
245
246
0
  if ((MagickPass == status) && (options.opacity_enabled))
247
0
    {
248
0
      status=QuantumOperatorImage(image,OpacityChannel,quantum_operator,
249
0
                                  options.values.opacity,&image->exception);
250
0
    }
251
252
0
  return status;
253
0
}
254

255
/*
256
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
257
%                                                                             %
258
%                                                                             %
259
%                                                                             %
260
%   Q u a n t u m O p e r a t o r R e g i o n I m a g e                       %
261
%                                                                             %
262
%                                                                             %
263
%                                                                             %
264
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
265
%
266
%  QuantumOperatorRegionImage() performs the requested arithmetic,
267
%  bitwise-logical, or value operation on the selected channels of
268
%  the image over the specified region. The AllChannels channel option
269
%  operates on all color channels whereas the GrayChannel channel option
270
%  treats the color channels as a grayscale intensity.
271
%
272
%  These operations are on the DirectClass pixels of the image and do not
273
%  update pixel indexes or colormap.
274
%
275
%  The format of the QuantumOperatorRegionImage method is:
276
%
277
%      MagickPassFail QuantumOperatorRegionImage(Image *image,
278
%        long x, long y, unsigned long columns, unsigned long rows,
279
%        ChannelType channel, QuantumOperator quantum_operator,
280
%        double rvalue)
281
%
282
%  A description of each parameter follows:
283
%
284
%    o image: The image.
285
%
286
%    o channel: Channel to operate on (RedChannel, CyanChannel,
287
%        GreenChannel, MagentaChannel, BlueChannel, YellowChannel,
288
%        OpacityChannel, BlackChannel, MatteChannel, AllChannels,
289
%        GrayChannel).  The AllChannels type only updates color
290
%        channels.  The GrayChannel type treats the color channels
291
%        as if they represent an intensity.
292
%
293
%    o x: Ordinate of left row of region.
294
%
295
%    o y: Ordinate of top column of region.
296
%
297
%    o columns: Width of region.
298
%
299
%    o rows: Height of region.
300
%
301
%    o quantum_operator: Operator to use (AddQuantumOp,AndQuantumOp,
302
%        AssignQuantumOp, DepthQuantumOp, DivideQuantumOp, GammaQuantumOp,
303
%        LShiftQuantumOp, MultiplyQuantumOp,  NegateQuantumOp,
304
%        NoiseGaussianQuantumOp, NoiseImpulseQuantumOp,
305
%        NoiseLaplacianQuantumOp, NoiseMultiplicativeQuantumOp,
306
%        NoisePoissonQuantumOp, NoiseRandomQuantumOp, NoiseUniformQuantumOp,
307
%        OrQuantumOp, RShiftQuantumOp, SubtractQuantumOp,
308
%        ThresholdBlackQuantumOp, ThresholdQuantumOp, ThresholdWhiteQuantumOp,
309
%        XorQuantumOp).
310
%
311
%    o rvalue: Operator argument.
312
%
313
%    o exception: Updated with error description.
314
%
315
*/
316
317
0
#define ApplyArithmeticOperator(lvalue,op,rvalue)       \
318
0
{                                                       \
319
0
    double                                              \
320
0
      result;                                           \
321
0
                                                        \
322
0
    result=(double) lvalue op (double) rvalue;          \
323
0
    lvalue=RoundDoubleToQuantum(result);                \
324
0
}
325
326
static MagickPassFail
327
QuantumAddCB(void *mutable_data,
328
             const void *immutable_data,
329
             Image * restrict image,
330
             PixelPacket * restrict pixels,
331
             IndexPacket * restrict indexes,
332
             const long npixels,
333
             ExceptionInfo *exception)
334
0
{
335
0
  const QuantumImmutableContext
336
0
    *context=(const QuantumImmutableContext *) immutable_data;
337
338
0
  register long
339
0
    i;
340
341
0
  ARG_NOT_USED(mutable_data);
342
0
  ARG_NOT_USED(image);
343
0
  ARG_NOT_USED(indexes);
344
0
  ARG_NOT_USED(exception);
345
346
0
  switch (context->channel)
347
0
    {
348
0
    case RedChannel:
349
0
    case CyanChannel:
350
0
      for (i=0; i < npixels; i++)
351
0
        ApplyArithmeticOperator(pixels[i].red,+,context->double_value);
352
0
      break;
353
0
    case GreenChannel:
354
0
    case MagentaChannel:
355
0
      for (i=0; i < npixels; i++)
356
0
        ApplyArithmeticOperator(pixels[i].green,+,context->double_value);
357
0
      break;
358
0
    case BlueChannel:
359
0
    case YellowChannel:
360
0
      for (i=0; i < npixels; i++)
361
0
        ApplyArithmeticOperator(pixels[i].blue,+,context->double_value);
362
0
      break;
363
0
    case BlackChannel:
364
0
    case MatteChannel:
365
0
    case OpacityChannel:
366
0
      for (i=0; i < npixels; i++)
367
0
        ApplyArithmeticOperator(pixels[i].opacity,+,context->double_value);
368
0
      break;
369
0
    case UndefinedChannel:
370
0
    case AllChannels:
371
0
      for (i=0; i < npixels; i++)
372
0
        {
373
0
          ApplyArithmeticOperator(pixels[i].red,+,context->double_value);
374
0
          ApplyArithmeticOperator(pixels[i].green,+,context->double_value);
375
0
          ApplyArithmeticOperator(pixels[i].blue,+,context->double_value);
376
0
        }
377
0
      break;
378
0
    case GrayChannel:
379
0
      for (i=0; i < npixels; i++)
380
0
        {
381
0
          Quantum
382
0
            intensity;
383
384
0
          intensity = PixelIntensity(&pixels[i]);
385
0
          ApplyArithmeticOperator(intensity,+,context->double_value);
386
0
          pixels[i].red = pixels[i].green = pixels[i].blue = intensity;
387
0
        }
388
0
      break;
389
0
    }
390
391
0
  return (MagickPass);
392
0
}
393
static MagickPassFail
394
QuantumAndCB(void *mutable_data,
395
             const void *immutable_data,
396
             Image * restrict image,
397
             PixelPacket * restrict pixels,
398
             IndexPacket * restrict indexes,
399
             const long npixels,
400
             ExceptionInfo *exception)
401
0
{
402
0
  const QuantumImmutableContext
403
0
    *context=(const QuantumImmutableContext *) immutable_data;
404
405
0
  register long
406
0
    i;
407
408
0
  ARG_NOT_USED(mutable_data);
409
0
  ARG_NOT_USED(image);
410
0
  ARG_NOT_USED(indexes);
411
0
  ARG_NOT_USED(exception);
412
413
0
  switch (context->channel)
414
0
    {
415
0
    case RedChannel:
416
0
    case CyanChannel:
417
0
      for (i=0; i < npixels; i++)
418
0
        pixels[i].red &= context->quantum_value;
419
0
      break;
420
0
    case GreenChannel:
421
0
    case MagentaChannel:
422
0
      for (i=0; i < npixels; i++)
423
0
        pixels[i].green &= context->quantum_value;
424
0
      break;
425
0
    case BlueChannel:
426
0
    case YellowChannel:
427
0
      for (i=0; i < npixels; i++)
428
0
        pixels[i].blue &= context->quantum_value;
429
0
      break;
430
0
    case BlackChannel:
431
0
    case MatteChannel:
432
0
    case OpacityChannel:
433
0
      for (i=0; i < npixels; i++)
434
0
        pixels[i].opacity &= context->quantum_value;
435
0
      break;
436
0
    case UndefinedChannel:
437
0
    case AllChannels:
438
0
      for (i=0; i < npixels; i++)
439
0
        {
440
0
          pixels[i].red &= context->quantum_value;
441
0
          pixels[i].green &= context->quantum_value;
442
0
          pixels[i].blue &= context->quantum_value;
443
0
        }
444
0
      break;
445
0
    case GrayChannel:
446
0
      for (i=0; i < npixels; i++)
447
0
        {
448
0
          Quantum
449
0
            intensity;
450
451
0
          intensity = PixelIntensity(&pixels[i]);
452
0
          intensity &= context->quantum_value;
453
0
          pixels[i].red = pixels[i].green = pixels[i].blue = intensity;
454
0
        }
455
0
      break;
456
0
    }
457
458
0
  return (MagickPass);
459
0
}
460
static MagickPassFail
461
QuantumAssignCB(void *mutable_data,
462
                const void *immutable_data,
463
                Image * restrict image,
464
                PixelPacket * restrict pixels,
465
                IndexPacket * restrict indexes,
466
                const long npixels,
467
                ExceptionInfo *exception)
468
0
{
469
0
  const QuantumImmutableContext
470
0
    *context=(const QuantumImmutableContext *) immutable_data;
471
472
0
  register long
473
0
    i;
474
475
0
  ARG_NOT_USED(mutable_data);
476
0
  ARG_NOT_USED(image);
477
0
  ARG_NOT_USED(indexes);
478
0
  ARG_NOT_USED(exception);
479
480
0
  switch (context->channel)
481
0
    {
482
0
    case RedChannel:
483
0
    case CyanChannel:
484
0
      for (i=0; i < npixels; i++)
485
0
        pixels[i].red = context->quantum_value;
486
0
      break;
487
0
    case GreenChannel:
488
0
    case MagentaChannel:
489
0
      for (i=0; i < npixels; i++)
490
0
        pixels[i].green = context->quantum_value;
491
0
      break;
492
0
    case BlueChannel:
493
0
    case YellowChannel:
494
0
      for (i=0; i < npixels; i++)
495
0
        pixels[i].blue = context->quantum_value;
496
0
      break;
497
0
    case BlackChannel:
498
0
    case MatteChannel:
499
0
    case OpacityChannel:
500
0
      for (i=0; i < npixels; i++)
501
0
        pixels[i].opacity = context->quantum_value;
502
0
      break;
503
0
    case UndefinedChannel:
504
0
    case AllChannels:
505
0
      for (i=0; i < npixels; i++)
506
0
        {
507
0
          pixels[i].red = context->quantum_value;
508
0
          pixels[i].green = context->quantum_value;
509
0
          pixels[i].blue = context->quantum_value;
510
0
        }
511
0
      break;
512
0
    case GrayChannel:
513
0
      for (i=0; i < npixels; i++)
514
0
        {
515
0
          pixels[i].red = pixels[i].green = pixels[i].blue =
516
0
            context->quantum_value;
517
0
        }
518
0
      break;
519
0
    }
520
521
0
  return (MagickPass);
522
0
}
523
#if 0
524
#define ApplyChannelDepth(parameter)                                    \
525
  {                                                                     \
526
    for (i=0; i < npixels; i++)                                         \
527
      parameter=scale*((parameter)/scale);                              \
528
  }
529
#endif
530
#if MaxRGB > MaxMap
531
#  define CrushChannelDepth(parameter) (scale*((parameter)/scale))
532
#else
533
0
#  define CrushChannelDepth(parameter) (mutable_context->channel_lut[ScaleQuantumToMap(parameter)])
534
#endif
535
static MagickPassFail
536
QuantumDepthCB(void *mutable_data,
537
               const void *immutable_data,
538
               Image * restrict image,
539
               PixelPacket * restrict pixels,
540
               IndexPacket * restrict indexes,
541
               const long npixels,
542
               ExceptionInfo *exception)
543
0
{
544
0
  QuantumMutableContext
545
0
    *mutable_context=(QuantumMutableContext *) mutable_data;
546
547
0
  const QuantumImmutableContext
548
0
    *immutable_context=(const QuantumImmutableContext *) immutable_data;
549
550
0
  unsigned int
551
0
    depth;
552
553
0
  unsigned int
554
0
    scale;
555
556
0
  register long
557
0
    i;
558
559
0
  MagickPassFail
560
0
    status=MagickPass;
561
562
0
  ARG_NOT_USED(mutable_data);
563
0
  ARG_NOT_USED(exception);
564
565
0
  depth=immutable_context->quantum_value;
566
0
  if (depth < 1)
567
0
    depth=1;
568
0
  else if (depth > QuantumDepth)
569
0
    depth=QuantumDepth;
570
571
0
  if (depth < QuantumDepth)
572
0
    {
573
0
      scale=MaxRGB / (MaxRGB >> (QuantumDepth-depth));
574
575
      /*
576
        Build LUT for Q8 and Q16 builds
577
      */
578
0
#if MaxRGB <= MaxMap
579
#  if defined(HAVE_OPENMP)
580
#    pragma omp critical (GM_QuantumDepthCB)
581
#  endif
582
0
      if (mutable_context->channel_lut == (Quantum *) NULL)
583
0
        {
584
0
          mutable_context->channel_lut=MagickAllocateArray(Quantum *, MaxMap+1,sizeof(Quantum));
585
0
          if (mutable_context->channel_lut == (Quantum *) NULL)
586
0
            status=MagickFail;
587
588
0
          if (mutable_context->channel_lut != (Quantum *) NULL)
589
0
            {
590
0
              unsigned int
591
0
                li;
592
593
0
              for (li=0; li <= MaxMap; li++)
594
0
                mutable_context->channel_lut[li] = scale*(li/scale);
595
0
            }
596
0
        }
597
598
0
      if (MagickFail == status)
599
0
        return status;
600
#else
601
      ARG_NOT_USED(*mutable_context);
602
      ARG_NOT_USED(status);
603
#endif
604
605
0
      switch (immutable_context->channel)
606
0
        {
607
0
        case RedChannel:
608
0
        case CyanChannel:
609
0
          for (i=0; i < npixels; i++)
610
0
            pixels[i].red=CrushChannelDepth(pixels[i].red);
611
0
          break;
612
0
        case GreenChannel:
613
0
        case MagentaChannel:
614
0
          for (i=0; i < npixels; i++)
615
0
            pixels[i].green=CrushChannelDepth(pixels[i].green);
616
0
          break;
617
0
        case BlueChannel:
618
0
        case YellowChannel:
619
0
          for (i=0; i < npixels; i++)
620
0
            pixels[i].blue=CrushChannelDepth(pixels[i].blue);
621
0
          break;
622
0
        case MatteChannel:
623
0
        case OpacityChannel:
624
0
          if (image->colorspace == CMYKColorspace)
625
0
            for (i=0; i < npixels; i++)
626
0
              indexes[i]=CrushChannelDepth(indexes[i]);
627
0
          else
628
0
            for (i=0; i < npixels; i++)
629
0
              pixels[i].opacity=CrushChannelDepth(pixels[i].opacity);
630
0
          break;
631
0
        case BlackChannel:
632
0
          for (i=0; i < npixels; i++)
633
0
            pixels[i].opacity=CrushChannelDepth(pixels[i].opacity);
634
0
          break;
635
0
        case UndefinedChannel:
636
0
        case AllChannels:
637
0
          for (i=0; i < npixels; i++)
638
0
            {
639
0
              pixels[i].red=CrushChannelDepth(pixels[i].red);
640
0
              pixels[i].green=CrushChannelDepth(pixels[i].green);
641
0
              pixels[i].blue=CrushChannelDepth(pixels[i].blue);
642
0
              if (image->colorspace == CMYKColorspace)
643
0
                pixels[i].opacity=CrushChannelDepth(pixels[i].opacity);
644
0
            }
645
0
          break;
646
0
        case GrayChannel:
647
0
          for (i=0; i < npixels; i++)
648
0
            {
649
0
              Quantum
650
0
                intensity;
651
652
0
              intensity = PixelIntensity(&pixels[i]);
653
0
              intensity=CrushChannelDepth(intensity);
654
0
              pixels[i].red = pixels[i].green = pixels[i].blue = intensity;
655
0
            }
656
0
          break;
657
0
        }
658
0
    }
659
660
0
  return MagickPass;
661
0
}
662
static MagickPassFail
663
QuantumDivideCB(void *mutable_data,
664
                const void *immutable_data,
665
                Image * restrict image,
666
                PixelPacket * restrict pixels,
667
                IndexPacket * restrict indexes,
668
                const long npixels,
669
                ExceptionInfo *exception)
670
0
{
671
0
  const QuantumImmutableContext
672
0
    *context=(const QuantumImmutableContext *) immutable_data;
673
674
0
  register long
675
0
    i;
676
677
0
  ARG_NOT_USED(mutable_data);
678
0
  ARG_NOT_USED(image);
679
0
  ARG_NOT_USED(indexes);
680
0
  ARG_NOT_USED(exception);
681
682
0
  switch (context->channel)
683
0
    {
684
0
    case RedChannel:
685
0
    case CyanChannel:
686
0
      for (i=0; i < npixels; i++)
687
0
        ApplyArithmeticOperator(pixels[i].red,/,context->double_value);
688
0
      break;
689
0
    case GreenChannel:
690
0
    case MagentaChannel:
691
0
      for (i=0; i < npixels; i++)
692
0
        ApplyArithmeticOperator(pixels[i].green,/,context->double_value);
693
0
      break;
694
0
    case BlueChannel:
695
0
    case YellowChannel:
696
0
      for (i=0; i < npixels; i++)
697
0
        ApplyArithmeticOperator(pixels[i].blue,/,context->double_value);
698
0
      break;
699
0
    case BlackChannel:
700
0
    case MatteChannel:
701
0
    case OpacityChannel:
702
0
      for (i=0; i < npixels; i++)
703
0
        ApplyArithmeticOperator(pixels[i].opacity,/,context->double_value);
704
0
      break;
705
0
    case UndefinedChannel:
706
0
    case AllChannels:
707
0
      for (i=0; i < npixels; i++)
708
0
        {
709
0
          ApplyArithmeticOperator(pixels[i].red,/,context->double_value);
710
0
          ApplyArithmeticOperator(pixels[i].green,/,context->double_value);
711
0
          ApplyArithmeticOperator(pixels[i].blue,/,context->double_value);
712
0
        }
713
0
      break;
714
0
    case GrayChannel:
715
0
      for (i=0; i < npixels; i++)
716
0
        {
717
0
          Quantum
718
0
            intensity;
719
720
0
          intensity = PixelIntensity(&pixels[i]);
721
0
          ApplyArithmeticOperator(intensity,/,context->double_value);
722
0
          pixels[i].red = pixels[i].green = pixels[i].blue = intensity;
723
0
        }
724
0
      break;
725
0
    }
726
727
0
  return (MagickPass);
728
0
}
729
#if MaxRGB > MaxMap
730
#  define GammaAdjustQuantum(quantum) (MaxRGBDouble*pow(quantum/MaxRGBDouble,1.0/immutable_context->double_value)+0.5)
731
#else
732
0
#  define GammaAdjustQuantum(quantum) (mutable_context->channel_lut[ScaleQuantumToMap(quantum)])
733
#endif
734
static MagickPassFail
735
QuantumGammaCB(void *mutable_data,
736
               const void *immutable_data,
737
               Image * restrict image,
738
               PixelPacket * restrict pixels,
739
               IndexPacket * restrict indexes,
740
               const long npixels,
741
               ExceptionInfo *exception)
742
0
{
743
0
  QuantumMutableContext
744
0
    *mutable_context=(QuantumMutableContext *) mutable_data;
745
746
0
  const QuantumImmutableContext
747
0
    *immutable_context=(const QuantumImmutableContext *) immutable_data;
748
749
0
  register long
750
0
    i;
751
752
0
  MagickPassFail
753
0
    status=MagickPass;
754
755
0
  ARG_NOT_USED(image);
756
0
  ARG_NOT_USED(indexes);
757
0
  ARG_NOT_USED(exception);
758
759
  /*
760
    Build LUT for Q8 and Q16 builds
761
  */
762
0
#if MaxRGB <= MaxMap
763
#  if defined(HAVE_OPENMP)
764
#    pragma omp critical (GM_QuantumGammaCB)
765
#  endif
766
0
  if (mutable_context->channel_lut == (Quantum *) NULL)
767
0
    {
768
0
      mutable_context->channel_lut=MagickAllocateArray(Quantum *, MaxMap+1,sizeof(Quantum));
769
0
      if (mutable_context->channel_lut == (Quantum *) NULL)
770
0
        status=MagickFail;
771
772
0
      if (mutable_context->channel_lut != (Quantum *) NULL)
773
0
        {
774
0
          for (i=0; i <= (long) MaxMap; i++)
775
0
            mutable_context->channel_lut[i] =
776
0
              ScaleMapToQuantum(MaxMap*pow((double) i/MaxMap,
777
0
                                           1.0/immutable_context->double_value));
778
0
        }
779
0
    }
780
781
0
  if (MagickFail == status)
782
0
    return status;
783
#else
784
  ARG_NOT_USED(*mutable_context);
785
  ARG_NOT_USED(status);
786
#endif
787
788
0
  switch (immutable_context->channel)
789
0
    {
790
0
    case RedChannel:
791
0
    case CyanChannel:
792
0
      for (i=0; i < npixels; i++)
793
0
        pixels[i].red=GammaAdjustQuantum(pixels[i].red);
794
0
      break;
795
0
    case GreenChannel:
796
0
    case MagentaChannel:
797
0
      for (i=0; i < npixels; i++)
798
0
        pixels[i].green=GammaAdjustQuantum(pixels[i].green);
799
0
      break;
800
0
    case BlueChannel:
801
0
    case YellowChannel:
802
0
      for (i=0; i < npixels; i++)
803
0
        pixels[i].blue=GammaAdjustQuantum(pixels[i].blue);
804
0
      break;
805
0
    case BlackChannel:
806
0
    case MatteChannel:
807
0
    case OpacityChannel:
808
0
      for (i=0; i < npixels; i++)
809
0
        pixels[i].opacity=GammaAdjustQuantum(pixels[i].opacity);
810
0
      break;
811
0
    case UndefinedChannel:
812
0
    case AllChannels:
813
0
      for (i=0; i < npixels; i++)
814
0
        {
815
0
          pixels[i].red=GammaAdjustQuantum(pixels[i].red);
816
0
          pixels[i].green=GammaAdjustQuantum(pixels[i].green);
817
0
          pixels[i].blue=GammaAdjustQuantum(pixels[i].blue);
818
0
        }
819
0
      break;
820
0
    case GrayChannel:
821
0
      for (i=0; i < npixels; i++)
822
0
        {
823
0
          Quantum
824
0
            intensity;
825
826
0
          intensity = PixelIntensity(&pixels[i]);
827
0
          intensity = GammaAdjustQuantum(intensity);
828
0
          pixels[i].red = pixels[i].green = pixels[i].blue = intensity;
829
0
        }
830
0
      break;
831
0
    }
832
833
0
  return status;
834
0
}
835
static MagickPassFail
836
QuantumNegateCB(void *mutable_data,
837
                const void *immutable_data,
838
                Image * restrict image,
839
                PixelPacket * restrict pixels,
840
                IndexPacket * restrict indexes,
841
                const long npixels,
842
                ExceptionInfo *exception)
843
0
{
844
0
  const QuantumImmutableContext
845
0
    *context=(const QuantumImmutableContext *) immutable_data;
846
847
0
  register long
848
0
    i;
849
850
0
  ARG_NOT_USED(mutable_data);
851
0
  ARG_NOT_USED(image);
852
0
  ARG_NOT_USED(indexes);
853
0
  ARG_NOT_USED(exception);
854
855
0
  switch (context->channel)
856
0
    {
857
0
    case RedChannel:
858
0
    case CyanChannel:
859
0
      for (i=0; i < npixels; i++)
860
0
        pixels[i].red=MaxRGB-pixels[i].red;
861
0
      break;
862
0
    case GreenChannel:
863
0
    case MagentaChannel:
864
0
      for (i=0; i < npixels; i++)
865
0
        pixels[i].green=MaxRGB-pixels[i].green;
866
0
      break;
867
0
    case BlueChannel:
868
0
    case YellowChannel:
869
0
      for (i=0; i < npixels; i++)
870
0
        pixels[i].blue=MaxRGB-pixels[i].blue;
871
0
      break;
872
0
    case BlackChannel:
873
0
    case MatteChannel:
874
0
    case OpacityChannel:
875
0
      for (i=0; i < npixels; i++)
876
0
        pixels[i].opacity=MaxRGB-pixels[i].opacity;
877
0
      break;
878
0
    case UndefinedChannel:
879
0
    case AllChannels:
880
0
      for (i=0; i < npixels; i++)
881
0
        {
882
0
          pixels[i].red=MaxRGB-pixels[i].red;
883
0
          pixels[i].green=MaxRGB-pixels[i].green;
884
0
          pixels[i].blue=MaxRGB-pixels[i].blue;
885
0
        }
886
0
      break;
887
0
    case GrayChannel:
888
0
      for (i=0; i < npixels; i++)
889
0
        {
890
0
          Quantum
891
0
            intensity;
892
893
0
          intensity = PixelIntensity(&pixels[i]);
894
0
          intensity = MaxRGB-intensity;
895
0
          pixels[i].red = pixels[i].green = pixels[i].blue = intensity;
896
0
        }
897
0
      break;
898
0
    }
899
900
0
  return (MagickPass);
901
0
}
902
/* log(quantum*value+1)/log(value+1) */
903
#if MaxRGB > MaxMap
904
#  define LogAdjustQuantum(quantum) \
905
  ((MaxRGBDouble*log((quantum/MaxRGBDouble)*immutable_context->double_value+1.0)/ \
906
    log(immutable_context->double_value+1.0))+0.5)
907
#else
908
0
#  define LogAdjustQuantum(quantum) (mutable_context->channel_lut[ScaleQuantumToMap(quantum)])
909
#endif
910
static MagickPassFail
911
QuantumLogCB(void *mutable_data,
912
             const void *immutable_data,
913
             Image * restrict image,
914
             PixelPacket * restrict pixels,
915
             IndexPacket * restrict indexes,
916
             const long npixels,
917
             ExceptionInfo *exception)
918
0
{
919
0
  QuantumMutableContext
920
0
    *mutable_context=(QuantumMutableContext *) mutable_data;
921
922
0
  const QuantumImmutableContext
923
0
    *immutable_context=(const QuantumImmutableContext *) immutable_data;
924
925
0
  register long
926
0
    i;
927
928
0
  MagickPassFail
929
0
    status=MagickPass;
930
931
0
  ARG_NOT_USED(image);
932
0
  ARG_NOT_USED(indexes);
933
0
  ARG_NOT_USED(exception);
934
935
  /*
936
    Build LUT for Q8 and Q16 builds
937
  */
938
0
#if MaxRGB <= MaxMap
939
#  if defined(HAVE_OPENMP)
940
#    pragma omp critical (GM_QuantumLogCB)
941
#  endif
942
0
  if (mutable_context->channel_lut == (Quantum *) NULL)
943
0
    {
944
0
      mutable_context->channel_lut=MagickAllocateArray(Quantum *, MaxMap+1,sizeof(Quantum));
945
0
      if (mutable_context->channel_lut == (Quantum *) NULL)
946
0
        status=MagickFail;
947
948
0
      if (mutable_context->channel_lut != (Quantum *) NULL)
949
0
        {
950
0
          for (i=0; i <= (long) MaxMap; i++)
951
0
            {
952
0
              double
953
0
                value;
954
955
0
              value=MaxRGBDouble*(log((ScaleMapToQuantum(i)/MaxRGBDouble)*
956
0
                                     immutable_context->double_value+1.0)/
957
0
                                  log(immutable_context->double_value+1.0));
958
0
              mutable_context->channel_lut[i] = RoundDoubleToQuantum(value);
959
0
            }
960
0
        }
961
0
    }
962
0
  if (MagickFail == status)
963
0
    return status;
964
#else
965
  ARG_NOT_USED(*mutable_context);
966
  ARG_NOT_USED(status);
967
#endif
968
0
  switch (immutable_context->channel)
969
0
    {
970
0
    case RedChannel:
971
0
    case CyanChannel:
972
0
      for (i=0; i < npixels; i++)
973
0
        pixels[i].red=LogAdjustQuantum(pixels[i].red);
974
0
      break;
975
0
    case GreenChannel:
976
0
    case MagentaChannel:
977
0
      for (i=0; i < npixels; i++)
978
0
        pixels[i].green=LogAdjustQuantum(pixels[i].green);
979
0
      break;
980
0
    case BlueChannel:
981
0
    case YellowChannel:
982
0
      for (i=0; i < npixels; i++)
983
0
        pixels[i].blue=LogAdjustQuantum(pixels[i].blue);
984
0
      break;
985
0
    case BlackChannel:
986
0
    case MatteChannel:
987
0
    case OpacityChannel:
988
0
      for (i=0; i < npixels; i++)
989
0
        pixels[i].opacity=LogAdjustQuantum(pixels[i].opacity);
990
0
      break;
991
0
    case UndefinedChannel:
992
0
    case AllChannels:
993
0
      for (i=0; i < npixels; i++)
994
0
        {
995
0
          pixels[i].red=LogAdjustQuantum(pixels[i].red);
996
0
          pixels[i].green=LogAdjustQuantum(pixels[i].green);
997
0
          pixels[i].blue=LogAdjustQuantum(pixels[i].blue);
998
0
        }
999
0
      break;
1000
0
    case GrayChannel:
1001
0
      for (i=0; i < npixels; i++)
1002
0
        {
1003
0
          Quantum
1004
0
            intensity;
1005
1006
0
          intensity = PixelIntensity(&pixels[i]);
1007
0
          intensity = LogAdjustQuantum(intensity);
1008
0
          pixels[i].red = pixels[i].green = pixels[i].blue = intensity;
1009
0
        }
1010
0
      break;
1011
0
    }
1012
1013
0
  return status;
1014
0
}
1015
static MagickPassFail
1016
QuantumLShiftCB(void *mutable_data,
1017
                const void *immutable_data,
1018
                Image * restrict image,
1019
                PixelPacket * restrict pixels,
1020
                IndexPacket * restrict indexes,
1021
                const long npixels,
1022
                ExceptionInfo *exception)
1023
0
{
1024
0
  const QuantumImmutableContext
1025
0
    *context=(const QuantumImmutableContext *) immutable_data;
1026
1027
0
  register long
1028
0
    i;
1029
1030
0
  ARG_NOT_USED(mutable_data);
1031
0
  ARG_NOT_USED(image);
1032
0
  ARG_NOT_USED(indexes);
1033
0
  ARG_NOT_USED(exception);
1034
1035
0
  switch (context->channel)
1036
0
    {
1037
0
    case RedChannel:
1038
0
    case CyanChannel:
1039
0
      for (i=0; i < npixels; i++)
1040
0
        pixels[i].red <<= context->quantum_value;
1041
0
      break;
1042
0
    case GreenChannel:
1043
0
    case MagentaChannel:
1044
0
      for (i=0; i < npixels; i++)
1045
0
        pixels[i].green <<= context->quantum_value;
1046
0
      break;
1047
0
    case BlueChannel:
1048
0
    case YellowChannel:
1049
0
      for (i=0; i < npixels; i++)
1050
0
        pixels[i].blue <<= context->quantum_value;
1051
0
      break;
1052
0
    case BlackChannel:
1053
0
    case MatteChannel:
1054
0
    case OpacityChannel:
1055
0
      for (i=0; i < npixels; i++)
1056
0
        pixels[i].opacity <<= context->quantum_value;
1057
0
      break;
1058
0
    case UndefinedChannel:
1059
0
    case AllChannels:
1060
0
      for (i=0; i < npixels; i++)
1061
0
        {
1062
0
          pixels[i].red <<= context->quantum_value;
1063
0
          pixels[i].green <<= context->quantum_value;
1064
0
          pixels[i].blue <<= context->quantum_value;
1065
0
        }
1066
0
      break;
1067
0
    case GrayChannel:
1068
0
      for (i=0; i < npixels; i++)
1069
0
        {
1070
0
          Quantum
1071
0
            intensity;
1072
1073
0
          intensity = PixelIntensity(&pixels[i]);
1074
0
          intensity <<= context->quantum_value;
1075
0
          pixels[i].red = pixels[i].green = pixels[i].blue = intensity;
1076
0
        }
1077
0
      break;
1078
0
    }
1079
1080
0
  return (MagickPass);
1081
0
}
1082
static MagickPassFail
1083
QuantumMaxCB(void *mutable_data,
1084
             const void *immutable_data,
1085
             Image * restrict image,
1086
             PixelPacket * restrict pixels,
1087
             IndexPacket * restrict indexes,
1088
             const long npixels,
1089
             ExceptionInfo *exception)
1090
0
{
1091
0
  const QuantumImmutableContext
1092
0
    *context=(const QuantumImmutableContext *) immutable_data;
1093
1094
0
  register long
1095
0
    i;
1096
1097
0
  ARG_NOT_USED(mutable_data);
1098
0
  ARG_NOT_USED(image);
1099
0
  ARG_NOT_USED(indexes);
1100
0
  ARG_NOT_USED(exception);
1101
1102
0
  switch (context->channel)
1103
0
    {
1104
0
    case RedChannel:
1105
0
    case CyanChannel:
1106
0
      for (i=0; i < npixels; i++)
1107
0
        if (context->quantum_value > pixels[i].red)
1108
0
          pixels[i].red = context->quantum_value;
1109
0
      break;
1110
0
    case GreenChannel:
1111
0
    case MagentaChannel:
1112
0
      for (i=0; i < npixels; i++)
1113
0
        if (context->quantum_value > pixels[i].green)
1114
0
          pixels[i].green = context->quantum_value;
1115
0
      break;
1116
0
    case BlueChannel:
1117
0
    case YellowChannel:
1118
0
      for (i=0; i < npixels; i++)
1119
0
        if (context->quantum_value > pixels[i].blue)
1120
0
          pixels[i].blue = context->quantum_value;
1121
0
      break;
1122
0
    case BlackChannel:
1123
0
    case MatteChannel:
1124
0
    case OpacityChannel:
1125
0
      for (i=0; i < npixels; i++)
1126
0
        if (context->quantum_value > pixels[i].opacity)
1127
0
          pixels[i].opacity = context->quantum_value;
1128
0
      break;
1129
0
    case UndefinedChannel:
1130
0
    case AllChannels:
1131
0
      for (i=0; i < npixels; i++)
1132
0
        {
1133
0
          if (context->quantum_value > pixels[i].red)
1134
0
            pixels[i].red = context->quantum_value;
1135
0
          if (context->quantum_value > pixels[i].green)
1136
0
            pixels[i].green = context->quantum_value;
1137
0
          if (context->quantum_value > pixels[i].blue)
1138
0
            pixels[i].blue = context->quantum_value;
1139
0
        }
1140
0
      break;
1141
0
    case GrayChannel:
1142
0
      for (i=0; i < npixels; i++)
1143
0
        {
1144
0
          Quantum
1145
0
            intensity;
1146
1147
0
          intensity = PixelIntensity(&pixels[i]);
1148
0
          if (context->quantum_value > intensity)
1149
0
            intensity = context->quantum_value;
1150
0
          pixels[i].red = pixels[i].green = pixels[i].blue = intensity;
1151
0
        }
1152
0
      break;
1153
0
    }
1154
1155
0
  return (MagickPass);
1156
0
}
1157
static MagickPassFail
1158
QuantumMinCB(void *mutable_data,
1159
             const void *immutable_data,
1160
             Image * restrict image,
1161
             PixelPacket * restrict pixels,
1162
             IndexPacket * restrict indexes,
1163
             const long npixels,
1164
             ExceptionInfo *exception)
1165
0
{
1166
0
  const QuantumImmutableContext
1167
0
    *context=(const QuantumImmutableContext *) immutable_data;
1168
1169
0
  register long
1170
0
    i;
1171
1172
0
  ARG_NOT_USED(mutable_data);
1173
0
  ARG_NOT_USED(image);
1174
0
  ARG_NOT_USED(indexes);
1175
0
  ARG_NOT_USED(exception);
1176
1177
0
  switch (context->channel)
1178
0
    {
1179
0
    case RedChannel:
1180
0
    case CyanChannel:
1181
0
      for (i=0; i < npixels; i++)
1182
0
        if (context->quantum_value < pixels[i].red)
1183
0
          pixels[i].red = context->quantum_value;
1184
0
      break;
1185
0
    case GreenChannel:
1186
0
    case MagentaChannel:
1187
0
      for (i=0; i < npixels; i++)
1188
0
        if (context->quantum_value < pixels[i].green)
1189
0
          pixels[i].green = context->quantum_value;
1190
0
      break;
1191
0
    case BlueChannel:
1192
0
    case YellowChannel:
1193
0
      for (i=0; i < npixels; i++)
1194
0
        if (context->quantum_value < pixels[i].blue)
1195
0
          pixels[i].blue = context->quantum_value;
1196
0
      break;
1197
0
    case BlackChannel:
1198
0
    case MatteChannel:
1199
0
    case OpacityChannel:
1200
0
      for (i=0; i < npixels; i++)
1201
0
        if (context->quantum_value < pixels[i].opacity)
1202
0
          pixels[i].opacity = context->quantum_value;
1203
0
      break;
1204
0
    case UndefinedChannel:
1205
0
    case AllChannels:
1206
0
      for (i=0; i < npixels; i++)
1207
0
        {
1208
0
          if (context->quantum_value < pixels[i].red)
1209
0
            pixels[i].red = context->quantum_value;
1210
0
          if (context->quantum_value < pixels[i].green)
1211
0
            pixels[i].green = context->quantum_value;
1212
0
          if (context->quantum_value < pixels[i].blue)
1213
0
            pixels[i].blue = context->quantum_value;
1214
0
        }
1215
0
      break;
1216
0
    case GrayChannel:
1217
0
      for (i=0; i < npixels; i++)
1218
0
        {
1219
0
          Quantum
1220
0
            intensity;
1221
1222
0
          intensity = PixelIntensity(&pixels[i]);
1223
0
          if (context->quantum_value < intensity)
1224
0
            intensity = context->quantum_value;
1225
0
          pixels[i].red = pixels[i].green = pixels[i].blue = intensity;
1226
0
        }
1227
0
      break;
1228
0
    }
1229
1230
0
  return (MagickPass);
1231
0
}
1232
static MagickPassFail
1233
QuantumMultiplyCB(void *mutable_data,
1234
                  const void *immutable_data,
1235
                  Image * restrict image,
1236
                  PixelPacket * restrict pixels,
1237
                  IndexPacket * restrict indexes,
1238
                  const long npixels,
1239
                  ExceptionInfo *exception)
1240
0
{
1241
0
  const QuantumImmutableContext
1242
0
    *context=(const QuantumImmutableContext *) immutable_data;
1243
1244
0
  register long
1245
0
    i;
1246
1247
0
  ARG_NOT_USED(mutable_data);
1248
0
  ARG_NOT_USED(image);
1249
0
  ARG_NOT_USED(indexes);
1250
0
  ARG_NOT_USED(exception);
1251
1252
0
  switch (context->channel)
1253
0
    {
1254
0
    case RedChannel:
1255
0
    case CyanChannel:
1256
0
      for (i=0; i < npixels; i++)
1257
0
        ApplyArithmeticOperator(pixels[i].red,*,context->double_value);
1258
0
      break;
1259
0
    case GreenChannel:
1260
0
    case MagentaChannel:
1261
0
      for (i=0; i < npixels; i++)
1262
0
        ApplyArithmeticOperator(pixels[i].green,*,context->double_value);
1263
0
      break;
1264
0
    case BlueChannel:
1265
0
    case YellowChannel:
1266
0
      for (i=0; i < npixels; i++)
1267
0
        ApplyArithmeticOperator(pixels[i].blue,*,context->double_value);
1268
0
      break;
1269
0
    case BlackChannel:
1270
0
    case MatteChannel:
1271
0
    case OpacityChannel:
1272
0
      for (i=0; i < npixels; i++)
1273
0
        ApplyArithmeticOperator(pixels[i].opacity,*,context->double_value);
1274
0
      break;
1275
0
    case UndefinedChannel:
1276
0
    case AllChannels:
1277
0
      for (i=0; i < npixels; i++)
1278
0
        {
1279
0
          ApplyArithmeticOperator(pixels[i].red,*,context->double_value);
1280
0
          ApplyArithmeticOperator(pixels[i].green,*,context->double_value);
1281
0
          ApplyArithmeticOperator(pixels[i].blue,*,context->double_value);
1282
0
        }
1283
0
      break;
1284
0
    case GrayChannel:
1285
0
      for (i=0; i < npixels; i++)
1286
0
        {
1287
0
          Quantum
1288
0
            intensity;
1289
1290
0
          intensity = PixelIntensity(&pixels[i]);
1291
0
          ApplyArithmeticOperator(intensity,*,context->double_value);
1292
0
          pixels[i].red = pixels[i].green = pixels[i].blue = intensity;
1293
0
        }
1294
0
      break;
1295
0
    }
1296
1297
0
  return (MagickPass);
1298
0
}
1299
1300
static inline Quantum
1301
GenerateQuantumNoise(const Quantum quantum,const NoiseType noise_type,
1302
                     const double factor,MagickRandomKernel *kernel)
1303
0
{
1304
0
  double
1305
0
    value;
1306
1307
0
  value = (double) quantum+
1308
0
    factor*GenerateDifferentialNoise((double) quantum,noise_type,kernel);
1309
0
  return RoundDoubleToQuantum(value);
1310
0
}
1311
1312
static MagickPassFail
1313
QuantumNoiseCB(void *mutable_data,
1314
               const void *immutable_data,
1315
               Image * restrict image,
1316
               PixelPacket * restrict pixels,
1317
               IndexPacket * restrict indexes,
1318
               const long npixels,
1319
               ExceptionInfo *exception,
1320
               const NoiseType noise_type
1321
               )
1322
0
{
1323
0
  const QuantumImmutableContext
1324
0
    *context=(const QuantumImmutableContext *) immutable_data;
1325
1326
0
  register long
1327
0
    i;
1328
1329
0
  double
1330
0
    factor;
1331
1332
0
  MagickRandomKernel
1333
0
    *kernel;
1334
1335
0
  ARG_NOT_USED(mutable_data);
1336
0
  ARG_NOT_USED(image);
1337
0
  ARG_NOT_USED(indexes);
1338
0
  ARG_NOT_USED(exception);
1339
1340
0
  kernel=AcquireMagickRandomKernel();
1341
0
  factor=context->double_value/MaxRGBDouble;
1342
1343
0
  switch (context->channel)
1344
0
    {
1345
0
    case RedChannel:
1346
0
    case CyanChannel:
1347
0
      for (i=0; i < npixels; i++)
1348
0
        pixels[i].red = GenerateQuantumNoise(pixels[i].red,noise_type,factor,kernel);
1349
0
      break;
1350
0
    case GreenChannel:
1351
0
    case MagentaChannel:
1352
0
      for (i=0; i < npixels; i++)
1353
0
        pixels[i].green = GenerateQuantumNoise(pixels[i].green,noise_type,factor,kernel);
1354
0
      break;
1355
0
    case BlueChannel:
1356
0
    case YellowChannel:
1357
0
      for (i=0; i < npixels; i++)
1358
0
        pixels[i].blue = GenerateQuantumNoise(pixels[i].blue,noise_type,factor,kernel);
1359
0
      break;
1360
0
    case BlackChannel:
1361
0
    case MatteChannel:
1362
0
    case OpacityChannel:
1363
0
      for (i=0; i < npixels; i++)
1364
0
        pixels[i].opacity = GenerateQuantumNoise(pixels[i].opacity,noise_type,factor,kernel);
1365
0
      break;
1366
0
    case UndefinedChannel:
1367
0
    case AllChannels:
1368
0
      for (i=0; i < npixels; i++)
1369
0
        {
1370
0
          pixels[i].red   = GenerateQuantumNoise(pixels[i].red,noise_type,factor,kernel);
1371
0
          pixels[i].green = GenerateQuantumNoise(pixels[i].green,noise_type,factor,kernel);
1372
0
          pixels[i].blue  = GenerateQuantumNoise(pixels[i].blue,noise_type,factor,kernel);
1373
0
        }
1374
0
      break;
1375
0
    case GrayChannel:
1376
0
      for (i=0; i < npixels; i++)
1377
0
        {
1378
0
          Quantum
1379
0
            intensity;
1380
1381
0
          intensity = PixelIntensity(&pixels[i]);
1382
0
          pixels[i].red = pixels[i].green = pixels[i].blue =
1383
0
            GenerateQuantumNoise(intensity,noise_type,factor,kernel);
1384
0
        }
1385
0
      break;
1386
0
    }
1387
1388
0
  return (MagickPass);
1389
0
}
1390
static MagickPassFail
1391
QuantumNoiseGaussianCB(void *mutable_data,
1392
                       const void *immutable_data,
1393
                       Image * restrict image,
1394
                       PixelPacket * restrict pixels,
1395
                       IndexPacket * restrict indexes,
1396
                       const long npixels,
1397
                       ExceptionInfo *exception)
1398
0
{
1399
0
  return
1400
0
    QuantumNoiseCB(mutable_data,immutable_data,image,pixels,indexes,npixels,exception,GaussianNoise);
1401
0
}
1402
static MagickPassFail
1403
QuantumNoiseImpulseCB(void *mutable_data,
1404
                      const void *immutable_data,
1405
                      Image * restrict image,
1406
                      PixelPacket * restrict pixels,
1407
                      IndexPacket * restrict indexes,
1408
                      const long npixels,
1409
                      ExceptionInfo *exception)
1410
0
{
1411
0
  return
1412
0
    QuantumNoiseCB(mutable_data,immutable_data,image,pixels,indexes,npixels,exception,ImpulseNoise);
1413
0
}
1414
static MagickPassFail
1415
QuantumNoiseLaplacianCB(void *mutable_data,
1416
                        const void *immutable_data,
1417
                        Image * restrict image,
1418
                        PixelPacket * restrict pixels,
1419
                        IndexPacket * restrict indexes,
1420
                        const long npixels,
1421
                        ExceptionInfo *exception)
1422
0
{
1423
0
  return
1424
0
    QuantumNoiseCB(mutable_data,immutable_data,image,pixels,indexes,npixels,exception,LaplacianNoise);
1425
0
}
1426
static MagickPassFail
1427
QuantumNoiseMultiplicativeCB(void *mutable_data,
1428
                             const void *immutable_data,
1429
                             Image * restrict image,
1430
                             PixelPacket * restrict pixels,
1431
                             IndexPacket * restrict indexes,
1432
                             const long npixels,
1433
                             ExceptionInfo *exception)
1434
0
{
1435
0
  return
1436
0
    QuantumNoiseCB(mutable_data,immutable_data,image,pixels,indexes,npixels,
1437
0
                 exception,MultiplicativeGaussianNoise);
1438
0
}
1439
static MagickPassFail
1440
QuantumNoisePoissonCB(void *mutable_data,
1441
                      const void *immutable_data,
1442
                      Image * restrict image,
1443
                      PixelPacket * restrict pixels,
1444
                      IndexPacket * restrict indexes,
1445
                      const long npixels,
1446
                      ExceptionInfo *exception)
1447
0
{
1448
0
  return
1449
0
    QuantumNoiseCB(mutable_data,immutable_data,image,pixels,indexes,npixels,exception,PoissonNoise);
1450
0
}
1451
1452
1453
static MagickPassFail
1454
QuantumNoiseRandomCB(void *mutable_data,
1455
                     const void *immutable_data,
1456
                      Image * restrict image,
1457
                      PixelPacket * restrict pixels,
1458
                      IndexPacket * restrict indexes,
1459
                      const long npixels,
1460
                      ExceptionInfo *exception)
1461
0
{
1462
0
  return
1463
0
    QuantumNoiseCB(mutable_data,immutable_data,image,pixels,indexes,npixels,exception,RandomNoise);
1464
0
}
1465
1466
static MagickPassFail
1467
QuantumNoiseUniformCB(void *mutable_data,
1468
                      const void *immutable_data,
1469
                      Image * restrict image,
1470
                      PixelPacket * restrict pixels,
1471
                      IndexPacket * restrict indexes,
1472
                      const long npixels,
1473
                      ExceptionInfo *exception)
1474
0
{
1475
0
  return
1476
0
    QuantumNoiseCB(mutable_data,immutable_data,image,pixels,indexes,npixels,exception,UniformNoise);
1477
0
}
1478
static MagickPassFail
1479
QuantumOrCB(void *mutable_data,
1480
            const void *immutable_data,
1481
            Image * restrict image,
1482
            PixelPacket * restrict pixels,
1483
            IndexPacket * restrict indexes,
1484
            const long npixels,
1485
            ExceptionInfo *exception)
1486
0
{
1487
0
  const QuantumImmutableContext
1488
0
    *context=(const QuantumImmutableContext *) immutable_data;
1489
1490
0
  register long
1491
0
    i;
1492
1493
0
  ARG_NOT_USED(mutable_data);
1494
0
  ARG_NOT_USED(image);
1495
0
  ARG_NOT_USED(indexes);
1496
0
  ARG_NOT_USED(exception);
1497
1498
0
  switch (context->channel)
1499
0
    {
1500
0
    case RedChannel:
1501
0
    case CyanChannel:
1502
0
      for (i=0; i < npixels; i++)
1503
0
        pixels[i].red |= context->quantum_value;
1504
0
      break;
1505
0
    case GreenChannel:
1506
0
    case MagentaChannel:
1507
0
      for (i=0; i < npixels; i++)
1508
0
        pixels[i].green |= context->quantum_value;
1509
0
      break;
1510
0
    case BlueChannel:
1511
0
    case YellowChannel:
1512
0
      for (i=0; i < npixels; i++)
1513
0
        pixels[i].blue |= context->quantum_value;
1514
0
      break;
1515
0
    case BlackChannel:
1516
0
    case MatteChannel:
1517
0
    case OpacityChannel:
1518
0
      for (i=0; i < npixels; i++)
1519
0
        pixels[i].opacity |= context->quantum_value;
1520
0
      break;
1521
0
    case UndefinedChannel:
1522
0
    case AllChannels:
1523
0
      for (i=0; i < npixels; i++)
1524
0
        {
1525
0
          pixels[i].red |= context->quantum_value;
1526
0
          pixels[i].green |= context->quantum_value;
1527
0
          pixels[i].blue |= context->quantum_value;
1528
0
        }
1529
0
      break;
1530
0
    case GrayChannel:
1531
0
      for (i=0; i < npixels; i++)
1532
0
        {
1533
0
          Quantum
1534
0
            intensity;
1535
1536
0
          intensity = PixelIntensity(&pixels[i]);
1537
0
          intensity |= context->quantum_value;
1538
0
          pixels[i].red = pixels[i].green = pixels[i].blue = intensity;
1539
0
        }
1540
0
      break;
1541
0
    }
1542
1543
0
  return (MagickPass);
1544
0
}
1545
#if MaxRGB > MaxMap
1546
#  define PowAdjustQuantum(quantum) (MaxRGBDouble*pow(quantum/MaxRGBDouble,immutable_context->double_value)+0.5)
1547
#else
1548
0
#  define PowAdjustQuantum(quantum) (mutable_context->channel_lut[ScaleQuantumToMap(quantum)])
1549
#endif
1550
static MagickPassFail
1551
QuantumPowCB(void *mutable_data,
1552
             const void *immutable_data,
1553
             Image * restrict image,
1554
             PixelPacket * restrict pixels,
1555
             IndexPacket * restrict indexes,
1556
             const long npixels,
1557
             ExceptionInfo *exception)
1558
0
{
1559
0
  QuantumMutableContext
1560
0
    *mutable_context=(QuantumMutableContext *) mutable_data;
1561
1562
0
  const QuantumImmutableContext
1563
0
    *immutable_context=(const QuantumImmutableContext *) immutable_data;
1564
1565
0
  register long
1566
0
    i;
1567
1568
0
  MagickPassFail
1569
0
    status=MagickPass;
1570
1571
0
  ARG_NOT_USED(image);
1572
0
  ARG_NOT_USED(indexes);
1573
0
  ARG_NOT_USED(exception);
1574
1575
  /*
1576
    Build LUT for Q8 and Q16 builds
1577
  */
1578
0
#if MaxRGB <= MaxMap
1579
#  if defined(HAVE_OPENMP)
1580
#    pragma omp critical (GM_QuantumPowCB)
1581
#  endif
1582
0
  if (mutable_context->channel_lut == (Quantum *) NULL)
1583
0
    {
1584
0
      mutable_context->channel_lut=MagickAllocateArray(Quantum *, MaxMap+1,sizeof(Quantum));
1585
0
      if (mutable_context->channel_lut == (Quantum *) NULL)
1586
0
        status=MagickFail;
1587
1588
0
      if (mutable_context->channel_lut != (Quantum *) NULL)
1589
0
        {
1590
0
          for (i=0; i <= (long) MaxMap; i++)
1591
0
            mutable_context->channel_lut[i] =
1592
0
              ScaleMapToQuantum(MaxMap*pow((double) i/MaxMap,
1593
0
                                           immutable_context->double_value));
1594
0
        }
1595
0
    }
1596
1597
0
  if (MagickFail == status)
1598
0
    return status;
1599
#else
1600
  ARG_NOT_USED(*mutable_context);
1601
  ARG_NOT_USED(status);
1602
#endif
1603
1604
0
  switch (immutable_context->channel)
1605
0
    {
1606
0
    case RedChannel:
1607
0
    case CyanChannel:
1608
0
      for (i=0; i < npixels; i++)
1609
0
        pixels[i].red=PowAdjustQuantum(pixels[i].red);
1610
0
      break;
1611
0
    case GreenChannel:
1612
0
    case MagentaChannel:
1613
0
      for (i=0; i < npixels; i++)
1614
0
        pixels[i].green=PowAdjustQuantum(pixels[i].green);
1615
0
      break;
1616
0
    case BlueChannel:
1617
0
    case YellowChannel:
1618
0
      for (i=0; i < npixels; i++)
1619
0
        pixels[i].blue=PowAdjustQuantum(pixels[i].blue);
1620
0
      break;
1621
0
    case BlackChannel:
1622
0
    case MatteChannel:
1623
0
    case OpacityChannel:
1624
0
      for (i=0; i < npixels; i++)
1625
0
        pixels[i].opacity=PowAdjustQuantum(pixels[i].opacity);
1626
0
      break;
1627
0
    case UndefinedChannel:
1628
0
    case AllChannels:
1629
0
      for (i=0; i < npixels; i++)
1630
0
        {
1631
0
          pixels[i].red=PowAdjustQuantum(pixels[i].red);
1632
0
          pixels[i].green=PowAdjustQuantum(pixels[i].green);
1633
0
          pixels[i].blue=PowAdjustQuantum(pixels[i].blue);
1634
0
        }
1635
0
      break;
1636
0
    case GrayChannel:
1637
0
      for (i=0; i < npixels; i++)
1638
0
        {
1639
0
          Quantum
1640
0
            intensity;
1641
1642
0
          intensity = PixelIntensity(&pixels[i]);
1643
0
          intensity = PowAdjustQuantum(intensity);
1644
0
          pixels[i].red = pixels[i].green = pixels[i].blue = intensity;
1645
0
        }
1646
0
      break;
1647
0
    }
1648
1649
0
  return status;
1650
0
}
1651
static MagickPassFail
1652
QuantumRShiftCB(void *mutable_data,
1653
                const void *immutable_data,
1654
                Image * restrict image,
1655
                PixelPacket * restrict pixels,
1656
                IndexPacket * restrict indexes,
1657
                const long npixels,
1658
                ExceptionInfo *exception)
1659
0
{
1660
0
  const QuantumImmutableContext
1661
0
    *context=(const QuantumImmutableContext *) immutable_data;
1662
1663
0
  register long
1664
0
    i;
1665
1666
0
  ARG_NOT_USED(mutable_data);
1667
0
  ARG_NOT_USED(image);
1668
0
  ARG_NOT_USED(indexes);
1669
0
  ARG_NOT_USED(exception);
1670
1671
0
  switch (context->channel)
1672
0
    {
1673
0
    case RedChannel:
1674
0
    case CyanChannel:
1675
0
      for (i=0; i < npixels; i++)
1676
0
        pixels[i].red >>= context->quantum_value;
1677
0
      break;
1678
0
    case GreenChannel:
1679
0
    case MagentaChannel:
1680
0
      for (i=0; i < npixels; i++)
1681
0
        pixels[i].green >>= context->quantum_value;
1682
0
      break;
1683
0
    case BlueChannel:
1684
0
    case YellowChannel:
1685
0
      for (i=0; i < npixels; i++)
1686
0
        pixels[i].blue >>= context->quantum_value;
1687
0
      break;
1688
0
    case BlackChannel:
1689
0
    case MatteChannel:
1690
0
    case OpacityChannel:
1691
0
      for (i=0; i < npixels; i++)
1692
0
        pixels[i].opacity >>= context->quantum_value;
1693
0
      break;
1694
0
    case UndefinedChannel:
1695
0
    case AllChannels:
1696
0
      for (i=0; i < npixels; i++)
1697
0
        {
1698
0
          pixels[i].red >>= context->quantum_value;
1699
0
          pixels[i].green >>= context->quantum_value;
1700
0
          pixels[i].blue >>= context->quantum_value;
1701
0
        }
1702
0
      break;
1703
0
    case GrayChannel:
1704
0
      for (i=0; i < npixels; i++)
1705
0
        {
1706
0
          Quantum
1707
0
            intensity;
1708
1709
0
          intensity = PixelIntensity(&pixels[i]);
1710
0
          intensity >>= context->quantum_value;
1711
0
          pixels[i].red = pixels[i].green = pixels[i].blue = intensity;
1712
0
        }
1713
0
      break;
1714
0
    }
1715
1716
0
  return (MagickPass);
1717
0
}
1718
static MagickPassFail
1719
QuantumSubtractCB(void *mutable_data,
1720
                  const void *immutable_data,
1721
                  Image * restrict image,
1722
                  PixelPacket * restrict pixels,
1723
                  IndexPacket * restrict indexes,
1724
                  const long npixels,
1725
                  ExceptionInfo *exception)
1726
0
{
1727
0
  const QuantumImmutableContext
1728
0
    *context=(const QuantumImmutableContext *) immutable_data;
1729
1730
0
  register long
1731
0
    i;
1732
1733
0
  ARG_NOT_USED(mutable_data);
1734
0
  ARG_NOT_USED(image);
1735
0
  ARG_NOT_USED(indexes);
1736
0
  ARG_NOT_USED(exception);
1737
1738
0
  switch (context->channel)
1739
0
    {
1740
0
    case RedChannel:
1741
0
    case CyanChannel:
1742
0
      for (i=0; i < npixels; i++)
1743
0
        ApplyArithmeticOperator(pixels[i].red,-,context->double_value);
1744
0
      break;
1745
0
    case GreenChannel:
1746
0
    case MagentaChannel:
1747
0
      for (i=0; i < npixels; i++)
1748
0
        ApplyArithmeticOperator(pixels[i].green,-,context->double_value);
1749
0
      break;
1750
0
    case BlueChannel:
1751
0
    case YellowChannel:
1752
0
      for (i=0; i < npixels; i++)
1753
0
        ApplyArithmeticOperator(pixels[i].blue,-,context->double_value);
1754
0
      break;
1755
0
    case BlackChannel:
1756
0
    case MatteChannel:
1757
0
    case OpacityChannel:
1758
0
      for (i=0; i < npixels; i++)
1759
0
        ApplyArithmeticOperator(pixels[i].opacity,-,context->double_value);
1760
0
      break;
1761
0
    case UndefinedChannel:
1762
0
    case AllChannels:
1763
0
      for (i=0; i < npixels; i++)
1764
0
        {
1765
0
          ApplyArithmeticOperator(pixels[i].red,-,context->double_value);
1766
0
          ApplyArithmeticOperator(pixels[i].green,-,context->double_value);
1767
0
          ApplyArithmeticOperator(pixels[i].blue,-,context->double_value);
1768
0
        }
1769
0
      break;
1770
0
    case GrayChannel:
1771
0
      for (i=0; i < npixels; i++)
1772
0
        {
1773
0
          Quantum
1774
0
            intensity;
1775
1776
0
          intensity = PixelIntensity(&pixels[i]);
1777
0
          ApplyArithmeticOperator(intensity,-,context->double_value);
1778
0
          pixels[i].red = pixels[i].green = pixels[i].blue = intensity;
1779
0
        }
1780
0
      break;
1781
0
    }
1782
1783
0
  return (MagickPass);
1784
0
}
1785
1786
static inline Quantum ApplyThresholdOperator(const Quantum quantum,
1787
                                             const Quantum threshold)
1788
0
{
1789
0
  Quantum
1790
0
    result;
1791
1792
0
  if (quantum > threshold)
1793
0
    result=MaxRGB;
1794
0
  else
1795
0
    result=0U;
1796
1797
0
  return result;
1798
0
}
1799
static MagickPassFail
1800
QuantumThresholdCB(void *mutable_data,
1801
                   const void *immutable_data,
1802
                   Image * restrict image,
1803
                   PixelPacket * restrict pixels,
1804
                   IndexPacket * restrict indexes,
1805
                   const long npixels,
1806
                   ExceptionInfo *exception)
1807
0
{
1808
0
  const QuantumImmutableContext
1809
0
    *context=(const QuantumImmutableContext *) immutable_data;
1810
1811
0
  register long
1812
0
    i;
1813
1814
0
  ARG_NOT_USED(mutable_data);
1815
0
  ARG_NOT_USED(image);
1816
0
  ARG_NOT_USED(indexes);
1817
0
  ARG_NOT_USED(exception);
1818
1819
0
  switch (context->channel)
1820
0
    {
1821
0
    case RedChannel:
1822
0
    case CyanChannel:
1823
0
      for (i=0; i < npixels; i++)
1824
0
        pixels[i].red = ApplyThresholdOperator(pixels[i].red,context->quantum_value);
1825
0
      break;
1826
0
    case GreenChannel:
1827
0
    case MagentaChannel:
1828
0
      for (i=0; i < npixels; i++)
1829
0
        pixels[i].green = ApplyThresholdOperator(pixels[i].green,context->quantum_value);
1830
0
      break;
1831
0
    case BlueChannel:
1832
0
    case YellowChannel:
1833
0
      for (i=0; i < npixels; i++)
1834
0
        pixels[i].blue = ApplyThresholdOperator(pixels[i].blue,context->quantum_value);
1835
0
      break;
1836
0
    case BlackChannel:
1837
0
    case MatteChannel:
1838
0
    case OpacityChannel:
1839
0
      for (i=0; i < npixels; i++)
1840
0
        pixels[i].opacity = ApplyThresholdOperator(pixels[i].opacity,context->quantum_value);
1841
0
      break;
1842
0
    case UndefinedChannel:
1843
0
    case AllChannels:
1844
0
    case GrayChannel:
1845
0
      for (i=0; i < npixels; i++)
1846
0
        {
1847
0
          Quantum
1848
0
            intensity;
1849
1850
0
          intensity = PixelIntensity(&pixels[i]);
1851
0
          pixels[i].red = pixels[i].green = pixels[i].blue =
1852
0
            ApplyThresholdOperator(intensity,context->quantum_value);
1853
0
        }
1854
0
      break;
1855
0
    }
1856
0
  return (MagickPass);
1857
0
}
1858
1859
static inline Quantum ApplyThresholdBlackOperator(const Quantum quantum,
1860
                                                  const Quantum threshold)
1861
0
{
1862
0
  Quantum
1863
0
    result;
1864
1865
0
  if (quantum < threshold)
1866
0
    result=0U;
1867
0
  else
1868
0
    result=quantum;
1869
1870
0
  return result;
1871
0
}
1872
static MagickPassFail
1873
QuantumThresholdBlackCB(void *mutable_data,
1874
                        const void *immutable_data,
1875
                        Image * restrict image,
1876
                        PixelPacket * restrict pixels,
1877
                        IndexPacket * restrict indexes,
1878
                        const long npixels,
1879
                        ExceptionInfo *exception)
1880
0
{
1881
0
  const QuantumImmutableContext
1882
0
    *context=(const QuantumImmutableContext *) immutable_data;
1883
1884
0
  register long
1885
0
    i;
1886
1887
0
  ARG_NOT_USED(mutable_data);
1888
0
  ARG_NOT_USED(image);
1889
0
  ARG_NOT_USED(indexes);
1890
0
  ARG_NOT_USED(exception);
1891
1892
0
  switch (context->channel)
1893
0
    {
1894
0
    case RedChannel:
1895
0
    case CyanChannel:
1896
0
      for (i=0; i < npixels; i++)
1897
0
        pixels[i].red = ApplyThresholdBlackOperator(pixels[i].red,context->quantum_value);
1898
0
      break;
1899
0
    case GreenChannel:
1900
0
    case MagentaChannel:
1901
0
      for (i=0; i < npixels; i++)
1902
0
        pixels[i].green = ApplyThresholdBlackOperator(pixels[i].green,context->quantum_value);
1903
0
      break;
1904
0
    case BlueChannel:
1905
0
    case YellowChannel:
1906
0
      for (i=0; i < npixels; i++)
1907
0
        pixels[i].blue = ApplyThresholdBlackOperator(pixels[i].blue,context->quantum_value);
1908
0
      break;
1909
0
    case BlackChannel:
1910
0
    case MatteChannel:
1911
0
    case OpacityChannel:
1912
0
      for (i=0; i < npixels; i++)
1913
0
        pixels[i].opacity = ApplyThresholdBlackOperator(pixels[i].opacity,context->quantum_value);
1914
0
      break;
1915
0
    case UndefinedChannel:
1916
0
    case AllChannels:
1917
      /*
1918
        For the all-channels case we bend the rules a bit and only
1919
        threshold to black if the computed intensity of the color
1920
        channels is less than the threshold.  This allows black
1921
        thresholding to work without causing a color shift.  If
1922
        individual channels need to be thresholded, then per-channel
1923
        thresholding will be required for each channel to be
1924
        thresholded.
1925
      */
1926
0
      for (i=0; i < npixels; i++)
1927
0
        {
1928
0
          Quantum
1929
0
            intensity;
1930
1931
0
          intensity = PixelIntensity(&pixels[i]);
1932
0
          if (0U == ApplyThresholdBlackOperator(intensity,context->quantum_value))
1933
0
            pixels[i].red=pixels[i].green=pixels[i].blue=0U;
1934
0
        }
1935
0
      break;
1936
0
    case GrayChannel:
1937
0
      for (i=0; i < npixels; i++)
1938
0
        {
1939
0
          Quantum
1940
0
            intensity;
1941
1942
0
          intensity = PixelIntensity(&pixels[i]);
1943
0
          pixels[i].red = pixels[i].green = pixels[i].blue =
1944
0
            ApplyThresholdBlackOperator(intensity,context->quantum_value);
1945
0
        }
1946
0
      break;
1947
0
    }
1948
0
  return (MagickPass);
1949
0
}
1950
1951
static inline Quantum ApplyThresholdWhiteOperator(const Quantum quantum,
1952
                                                  const Quantum threshold)
1953
0
{
1954
0
  Quantum
1955
0
    result;
1956
1957
0
  if (quantum > threshold)
1958
0
    result=MaxRGB;
1959
0
  else
1960
0
    result=quantum;
1961
1962
0
  return result;
1963
0
}
1964
static MagickPassFail
1965
QuantumThresholdWhiteCB(void *mutable_data,
1966
                        const void *immutable_data,
1967
                        Image * restrict image,
1968
                        PixelPacket * restrict pixels,
1969
                        IndexPacket * restrict indexes,
1970
                        const long npixels,
1971
                        ExceptionInfo *exception)
1972
0
{
1973
0
  const QuantumImmutableContext
1974
0
    *context=(const QuantumImmutableContext *) immutable_data;
1975
1976
0
  register long
1977
0
    i;
1978
1979
0
  ARG_NOT_USED(mutable_data);
1980
0
  ARG_NOT_USED(image);
1981
0
  ARG_NOT_USED(indexes);
1982
0
  ARG_NOT_USED(exception);
1983
1984
0
  switch (context->channel)
1985
0
    {
1986
0
    case RedChannel:
1987
0
    case CyanChannel:
1988
0
      for (i=0; i < npixels; i++)
1989
0
        pixels[i].red = ApplyThresholdWhiteOperator(pixels[i].red,context->quantum_value);
1990
0
      break;
1991
0
    case GreenChannel:
1992
0
    case MagentaChannel:
1993
0
      for (i=0; i < npixels; i++)
1994
0
        pixels[i].green = ApplyThresholdWhiteOperator(pixels[i].green,context->quantum_value);
1995
0
      break;
1996
0
    case BlueChannel:
1997
0
    case YellowChannel:
1998
0
      for (i=0; i < npixels; i++)
1999
0
        pixels[i].blue = ApplyThresholdWhiteOperator(pixels[i].blue,context->quantum_value);
2000
0
      break;
2001
0
    case BlackChannel:
2002
0
    case MatteChannel:
2003
0
    case OpacityChannel:
2004
0
      for (i=0; i < npixels; i++)
2005
0
        pixels[i].opacity = ApplyThresholdWhiteOperator(pixels[i].opacity,context->quantum_value);
2006
0
      break;
2007
0
    case UndefinedChannel:
2008
0
    case AllChannels:
2009
      /*
2010
        For the all-channels case we bend the rules a bit and only
2011
        threshold to white if the computed intensity of the color
2012
        channels exceeds the threshold.  This allows white
2013
        thresholding to work without causing a color shift.  If
2014
        individual channels need to be thresholded, then per-channel
2015
        thresholding will be required for each channel to be
2016
        thresholded.
2017
      */
2018
0
      for (i=0; i < npixels; i++)
2019
0
        {
2020
0
          Quantum
2021
0
            intensity;
2022
2023
0
          intensity = PixelIntensity(&pixels[i]);
2024
0
          if (MaxRGB == ApplyThresholdWhiteOperator(intensity,context->quantum_value))
2025
0
            pixels[i].red=pixels[i].green=pixels[i].blue=MaxRGB;
2026
0
        }
2027
0
      break;
2028
0
    case GrayChannel:
2029
0
      for (i=0; i < npixels; i++)
2030
0
        {
2031
0
          Quantum
2032
0
            intensity;
2033
2034
0
          intensity = PixelIntensity(&pixels[i]);
2035
0
          pixels[i].red = pixels[i].green = pixels[i].blue =
2036
0
            ApplyThresholdWhiteOperator(intensity,context->quantum_value);
2037
0
        }
2038
0
      break;
2039
0
    }
2040
0
  return (MagickPass);
2041
0
}
2042
2043
static inline Quantum ApplyThresholdBlackNegateOperator(const Quantum intensity,
2044
                                                        const Quantum quantum,
2045
                                                        const Quantum threshold)
2046
0
{
2047
0
  Quantum
2048
0
    result;
2049
2050
0
  if (intensity < threshold)
2051
0
    result=MaxRGB;
2052
0
  else
2053
0
    result=quantum;
2054
2055
0
  return result;
2056
0
}
2057
static MagickPassFail
2058
QuantumThresholdBlackNegateCB(void *mutable_data,
2059
                              const void *immutable_data,
2060
                              Image * restrict image,
2061
                              PixelPacket * restrict pixels,
2062
                              IndexPacket * restrict indexes,
2063
                              const long npixels,
2064
                              ExceptionInfo *exception)
2065
0
{
2066
0
  const QuantumImmutableContext
2067
0
    *context=(const QuantumImmutableContext *) immutable_data;
2068
2069
0
  register long
2070
0
    i;
2071
2072
0
  ARG_NOT_USED(mutable_data);
2073
0
  ARG_NOT_USED(image);
2074
0
  ARG_NOT_USED(indexes);
2075
0
  ARG_NOT_USED(exception);
2076
2077
0
  switch (context->channel)
2078
0
    {
2079
0
    case RedChannel:
2080
0
    case CyanChannel:
2081
0
      for (i=0; i < npixels; i++)
2082
0
        pixels[i].red = ApplyThresholdBlackNegateOperator(pixels[i].red,pixels[i].red,context->quantum_value);
2083
0
      break;
2084
0
    case GreenChannel:
2085
0
    case MagentaChannel:
2086
0
      for (i=0; i < npixels; i++)
2087
0
        pixels[i].green = ApplyThresholdBlackNegateOperator(pixels[i].green,pixels[i].green,context->quantum_value);
2088
0
      break;
2089
0
    case BlueChannel:
2090
0
    case YellowChannel:
2091
0
      for (i=0; i < npixels; i++)
2092
0
        pixels[i].blue = ApplyThresholdBlackNegateOperator(pixels[i].blue,pixels[i].blue,context->quantum_value);
2093
0
      break;
2094
0
    case BlackChannel:
2095
0
    case MatteChannel:
2096
0
    case OpacityChannel:
2097
0
      for (i=0; i < npixels; i++)
2098
0
        pixels[i].opacity = ApplyThresholdBlackNegateOperator(pixels[i].opacity,pixels[i].opacity,context->quantum_value);
2099
0
      break;
2100
0
    case UndefinedChannel:
2101
0
    case AllChannels:
2102
      /*
2103
        For the all-channels case we bend the rules a bit and only
2104
        threshold to black if the computed intensity of the color
2105
        channels is less than the threshold.  This allows black
2106
        thresholding to work without causing a color shift.  If
2107
        individual channels need to be thresholded, then per-channel
2108
        thresholding will be required for each channel to be
2109
        thresholded.
2110
      */
2111
0
      for (i=0; i < npixels; i++)
2112
0
        {
2113
0
          Quantum
2114
0
            intensity;
2115
2116
0
          intensity = PixelIntensity(&pixels[i]);
2117
0
          pixels[i].red=ApplyThresholdBlackNegateOperator(intensity,pixels[i].red,context->quantum_value);
2118
0
          pixels[i].green=ApplyThresholdBlackNegateOperator(intensity,pixels[i].green,context->quantum_value);
2119
0
          pixels[i].blue=ApplyThresholdBlackNegateOperator(intensity,pixels[i].blue,context->quantum_value);
2120
0
        }
2121
0
      break;
2122
0
    case GrayChannel:
2123
0
      for (i=0; i < npixels; i++)
2124
0
        {
2125
0
          Quantum
2126
0
            intensity;
2127
2128
0
          intensity = PixelIntensity(&pixels[i]);
2129
0
          pixels[i].red = pixels[i].green = pixels[i].blue =
2130
0
            ApplyThresholdBlackNegateOperator(intensity,intensity,context->quantum_value);
2131
0
        }
2132
0
      break;
2133
0
    }
2134
0
  return (MagickPass);
2135
0
}
2136
2137
static inline Quantum ApplyThresholdWhiteNegateOperator(const Quantum intensity,
2138
                                                        const Quantum quantum,
2139
                                                        const Quantum threshold)
2140
0
{
2141
0
  Quantum
2142
0
    result;
2143
2144
0
  if (intensity > threshold)
2145
0
    result=0U;
2146
0
  else
2147
0
    result=quantum;
2148
2149
0
  return result;
2150
0
}
2151
static MagickPassFail
2152
QuantumThresholdWhiteNegateCB(void *mutable_data,
2153
                              const void *immutable_data,
2154
                              Image * restrict image,
2155
                              PixelPacket * restrict pixels,
2156
                              IndexPacket * restrict indexes,
2157
                              const long npixels,
2158
                              ExceptionInfo *exception)
2159
0
{
2160
0
  const QuantumImmutableContext
2161
0
    *context=(const QuantumImmutableContext *) immutable_data;
2162
2163
0
  register long
2164
0
    i;
2165
2166
0
  ARG_NOT_USED(mutable_data);
2167
0
  ARG_NOT_USED(image);
2168
0
  ARG_NOT_USED(indexes);
2169
0
  ARG_NOT_USED(exception);
2170
2171
0
  switch (context->channel)
2172
0
    {
2173
0
    case RedChannel:
2174
0
    case CyanChannel:
2175
0
      for (i=0; i < npixels; i++)
2176
0
        pixels[i].red = ApplyThresholdWhiteNegateOperator(pixels[i].red,pixels[i].red,context->quantum_value);
2177
0
      break;
2178
0
    case GreenChannel:
2179
0
    case MagentaChannel:
2180
0
      for (i=0; i < npixels; i++)
2181
0
        pixels[i].green = ApplyThresholdWhiteNegateOperator(pixels[i].green,pixels[i].green,context->quantum_value);
2182
0
      break;
2183
0
    case BlueChannel:
2184
0
    case YellowChannel:
2185
0
      for (i=0; i < npixels; i++)
2186
0
        pixels[i].blue = ApplyThresholdWhiteNegateOperator(pixels[i].blue,pixels[i].blue,context->quantum_value);
2187
0
      break;
2188
0
    case BlackChannel:
2189
0
    case MatteChannel:
2190
0
    case OpacityChannel:
2191
0
      for (i=0; i < npixels; i++)
2192
0
        pixels[i].opacity = ApplyThresholdWhiteNegateOperator(pixels[i].opacity,pixels[i].opacity,context->quantum_value);
2193
0
      break;
2194
0
    case UndefinedChannel:
2195
0
    case AllChannels:
2196
      /*
2197
        For the all-channels case we bend the rules a bit and only
2198
        threshold to white if the computed intensity of the color
2199
        channels exceeds the threshold.  This allows white
2200
        thresholding to work without causing a color shift.  If
2201
        individual channels need to be thresholded, then per-channel
2202
        thresholding will be required for each channel to be
2203
        thresholded.
2204
      */
2205
0
      for (i=0; i < npixels; i++)
2206
0
        {
2207
0
          Quantum
2208
0
            intensity;
2209
2210
0
          intensity = PixelIntensity(&pixels[i]);
2211
0
          pixels[i].red = ApplyThresholdWhiteNegateOperator(intensity,pixels[i].red,context->quantum_value);
2212
0
          pixels[i].green = ApplyThresholdWhiteNegateOperator(intensity,pixels[i].green,context->quantum_value);
2213
0
          pixels[i].blue = ApplyThresholdWhiteNegateOperator(intensity,pixels[i].blue,context->quantum_value);
2214
0
        }
2215
0
      break;
2216
0
    case GrayChannel:
2217
0
      for (i=0; i < npixels; i++)
2218
0
        {
2219
0
          Quantum
2220
0
            intensity;
2221
2222
0
          intensity = PixelIntensity(&pixels[i]);
2223
0
          pixels[i].red = pixels[i].green = pixels[i].blue =
2224
0
            ApplyThresholdWhiteNegateOperator(intensity,intensity,context->quantum_value);
2225
0
        }
2226
0
      break;
2227
0
    }
2228
0
  return (MagickPass);
2229
0
}
2230
2231
static MagickPassFail
2232
QuantumXorCB(void *mutable_data,
2233
             const void *immutable_data,
2234
             Image * restrict image,
2235
             PixelPacket * restrict pixels,
2236
             IndexPacket * restrict indexes,
2237
             const long npixels,
2238
             ExceptionInfo *exception)
2239
0
{
2240
0
  const QuantumImmutableContext
2241
0
    *context=(const QuantumImmutableContext *) immutable_data;
2242
2243
0
  register long
2244
0
    i;
2245
2246
0
  ARG_NOT_USED(mutable_data);
2247
0
  ARG_NOT_USED(image);
2248
0
  ARG_NOT_USED(indexes);
2249
0
  ARG_NOT_USED(exception);
2250
2251
0
  switch (context->channel)
2252
0
    {
2253
0
    case RedChannel:
2254
0
    case CyanChannel:
2255
0
      for (i=0; i < npixels; i++)
2256
0
        pixels[i].red ^= context->quantum_value;
2257
0
      break;
2258
0
    case GreenChannel:
2259
0
    case MagentaChannel:
2260
0
      for (i=0; i < npixels; i++)
2261
0
        pixels[i].green ^= context->quantum_value;
2262
0
      break;
2263
0
    case BlueChannel:
2264
0
    case YellowChannel:
2265
0
      for (i=0; i < npixels; i++)
2266
0
        pixels[i].blue ^= context->quantum_value;
2267
0
      break;
2268
0
    case BlackChannel:
2269
0
    case MatteChannel:
2270
0
    case OpacityChannel:
2271
0
      for (i=0; i < npixels; i++)
2272
0
        pixels[i].opacity ^= context->quantum_value;
2273
0
      break;
2274
0
    case UndefinedChannel:
2275
0
    case AllChannels:
2276
0
      for (i=0; i < npixels; i++)
2277
0
        {
2278
0
          pixels[i].red ^= context->quantum_value;
2279
0
          pixels[i].green ^= context->quantum_value;
2280
0
          pixels[i].blue ^= context->quantum_value;
2281
0
        }
2282
0
      break;
2283
0
    case GrayChannel:
2284
0
      for (i=0; i < npixels; i++)
2285
0
        {
2286
0
          Quantum
2287
0
            intensity;
2288
2289
0
          intensity = PixelIntensity(&pixels[i]);
2290
0
          intensity ^= context->quantum_value;
2291
0
          pixels[i].red = pixels[i].green = pixels[i].blue = intensity;
2292
0
        }
2293
0
      break;
2294
0
    }
2295
0
  return (MagickPass);
2296
0
}
2297
MagickExport MagickPassFail
2298
QuantumOperatorRegionImage(Image *image,
2299
                           const long x,const long y,
2300
                           const unsigned long columns,
2301
                           const unsigned long rows,
2302
                           const ChannelType channel,
2303
                           const QuantumOperator quantum_operator,
2304
                           const double rvalue,
2305
                           ExceptionInfo *exception)
2306
0
{
2307
0
  char
2308
0
    description[MaxTextExtent];
2309
2310
0
  QuantumImmutableContext
2311
0
    immutable_context;
2312
2313
0
  QuantumMutableContext
2314
0
    mutable_context;
2315
2316
0
  MagickPassFail
2317
0
    status = MagickFail;
2318
2319
0
  PixelIteratorMonoModifyCallback
2320
0
    call_back = 0;
2321
2322
0
  image->storage_class=DirectClass;
2323
2324
0
  immutable_context.channel=channel;
2325
0
  immutable_context.double_value=rvalue;
2326
0
  immutable_context.quantum_value=RoundDoubleToQuantum(rvalue);
2327
2328
0
  mutable_context.channel_lut=(Quantum *) NULL;
2329
2330
0
  switch (quantum_operator)
2331
0
    {
2332
0
    case UndefinedQuantumOp:
2333
0
      break;
2334
0
    case AddQuantumOp:
2335
0
      call_back=QuantumAddCB;
2336
0
      break;
2337
0
    case AndQuantumOp:
2338
0
      call_back=QuantumAndCB;
2339
0
      break;
2340
0
    case AssignQuantumOp:
2341
0
      call_back=QuantumAssignCB;
2342
0
      break;
2343
0
    case DivideQuantumOp:
2344
0
      call_back=QuantumDivideCB;
2345
0
      break;
2346
0
    case LShiftQuantumOp:
2347
0
      call_back=QuantumLShiftCB;
2348
0
      break;
2349
0
    case MultiplyQuantumOp:
2350
0
      call_back=QuantumMultiplyCB;
2351
0
      break;
2352
0
    case OrQuantumOp:
2353
0
      call_back=QuantumOrCB;
2354
0
      break;
2355
0
    case RShiftQuantumOp:
2356
0
      call_back=QuantumRShiftCB;
2357
0
      break;
2358
0
    case SubtractQuantumOp:
2359
0
      call_back=QuantumSubtractCB;
2360
0
      break;
2361
0
    case ThresholdQuantumOp:
2362
0
      call_back=QuantumThresholdCB;
2363
0
      break;
2364
0
    case ThresholdBlackQuantumOp:
2365
0
      call_back=QuantumThresholdBlackCB;
2366
0
      break;
2367
0
    case ThresholdWhiteQuantumOp:
2368
0
      call_back=QuantumThresholdWhiteCB;
2369
0
      break;
2370
0
    case ThresholdBlackNegateQuantumOp:
2371
0
      call_back=QuantumThresholdBlackNegateCB;
2372
0
      break;
2373
0
    case ThresholdWhiteNegateQuantumOp:
2374
0
      call_back=QuantumThresholdWhiteNegateCB;
2375
0
      break;
2376
0
    case XorQuantumOp:
2377
0
      call_back=QuantumXorCB;
2378
0
      break;
2379
0
    case NoiseGaussianQuantumOp:
2380
0
      call_back=QuantumNoiseGaussianCB;
2381
0
      break;
2382
0
    case NoiseImpulseQuantumOp:
2383
0
      call_back=QuantumNoiseImpulseCB;
2384
0
      break;
2385
0
    case NoiseLaplacianQuantumOp:
2386
0
      call_back=QuantumNoiseLaplacianCB;
2387
0
      break;
2388
0
    case NoiseMultiplicativeQuantumOp:
2389
0
      call_back=QuantumNoiseMultiplicativeCB;
2390
0
      break;
2391
0
    case NoisePoissonQuantumOp:
2392
0
      call_back=QuantumNoisePoissonCB;
2393
0
      break;
2394
0
    case NoiseUniformQuantumOp:
2395
0
      call_back=QuantumNoiseUniformCB;
2396
0
      break;
2397
0
    case NegateQuantumOp:
2398
0
      call_back=QuantumNegateCB;
2399
0
      break;
2400
0
    case GammaQuantumOp:
2401
0
      call_back=QuantumGammaCB;
2402
0
      break;
2403
0
    case DepthQuantumOp:
2404
0
      call_back=QuantumDepthCB;
2405
0
      break;
2406
0
    case LogQuantumOp:
2407
0
      call_back=QuantumLogCB;
2408
0
      break;
2409
0
    case MaxQuantumOp:
2410
0
      call_back=QuantumMaxCB;
2411
0
      break;
2412
0
    case MinQuantumOp:
2413
0
      call_back=QuantumMinCB;
2414
0
      break;
2415
0
    case PowQuantumOp:
2416
0
      call_back=QuantumPowCB;
2417
0
      break;
2418
0
    case NoiseRandomQuantumOp:
2419
0
      call_back=QuantumNoiseRandomCB;
2420
0
      break;
2421
0
    }
2422
2423
0
  if (call_back)
2424
0
    {
2425
0
      FormatString(description,"[%%s] Apply operator '%s %g (%g%%%%)' to channel '%s'...",
2426
0
                   QuantumOperatorToString(quantum_operator),rvalue,
2427
0
                   ((rvalue/MaxRGBFloat)*100),
2428
0
                   ChannelTypeToString(channel));
2429
0
      status=PixelIterateMonoModify(call_back,
2430
0
                                    NULL,
2431
0
                                    description,
2432
0
                                    &mutable_context,&immutable_context,x,y,columns,rows,
2433
0
                                    image,exception);
2434
2435
      /*
2436
        Free any channel LUT.
2437
      */
2438
0
      MagickFreeMemory(mutable_context.channel_lut);
2439
2440
      /*
2441
        If we are assigning all the color channels in the entire image
2442
        then set monochrome and grayscale flags.
2443
      */
2444
0
      if ((quantum_operator == AssignQuantumOp) &&
2445
0
          (channel == AllChannels) && (x == 0) && (y == 0) &&
2446
0
          (columns == image->columns) && (rows == image->rows))
2447
0
        {
2448
0
          image->is_monochrome=MagickTrue;
2449
0
          image->is_grayscale=MagickTrue;
2450
0
        }
2451
0
    }
2452
0
  return (status);
2453
0
}