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