MagickCore 6.9.13
Loading...
Searching...
No Matches
channel.c
1/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3% %
4% %
5% %
6% CCCC H H AAA N N N N EEEEE L %
7% C H H A A NN N NN N E L %
8% C HHHHH AAAAA N N N N N N EEE L %
9% C H H A A N NN N NN E L %
10% CCCC H H A A N N N N EEEEE LLLLL %
11% %
12% %
13% MagickCore Image Channel Methods %
14% %
15% Software Design %
16% Cristy %
17% December 2003 %
18% %
19% %
20% Copyright 1999 ImageMagick Studio LLC, a non-profit organization %
21% dedicated to making software imaging solutions freely available. %
22% %
23% You may not use this file except in compliance with the License. You may %
24% obtain a copy of the License at %
25% %
26% https://imagemagick.org/script/license.php %
27% %
28% Unless required by applicable law or agreed to in writing, software %
29% distributed under the License is distributed on an "AS IS" BASIS, %
30% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31% See the License for the specific language governing permissions and %
32% limitations under the License. %
33% %
34%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35%
36%
37%
38*/
39
40/*
41 Include declarations.
42*/
43#include "magick/studio.h"
44#include "magick/cache-private.h"
45#include "magick/channel.h"
46#include "magick/color-private.h"
47#include "magick/colorspace-private.h"
48#include "magick/composite-private.h"
49#include "magick/exception-private.h"
50#include "magick/enhance.h"
51#include "magick/image.h"
52#include "magick/list.h"
53#include "magick/log.h"
54#include "magick/monitor.h"
55#include "magick/monitor-private.h"
56#include "magick/option.h"
57#include "magick/pixel-accessor.h"
58#include "magick/resource_.h"
59#include "magick/string-private.h"
60#include "magick/thread-private.h"
61#include "magick/token.h"
62#include "magick/utility.h"
63#include "magick/version.h"
64
65/*
66%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
67% %
68% %
69% %
70% C o m b i n e I m a g e s %
71% %
72% %
73% %
74%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
75%
76% CombineImages() combines one or more images into a single image. The
77% grayscale value of the pixels of each image in the sequence is assigned in
78% order to the specified channels of the combined image. The typical
79% ordering would be image 1 => Red, 2 => Green, 3 => Blue, etc.
80%
81% The format of the CombineImages method is:
82%
83% Image *CombineImages(const Image *image,const ChannelType channel,
84% ExceptionInfo *exception)
85%
86% A description of each parameter follows:
87%
88% o image: the image.
89%
90% o exception: return any errors or warnings in this structure.
91%
92*/
93MagickExport Image *CombineImages(const Image *image,const ChannelType channel,
94 ExceptionInfo *exception)
95{
96#define CombineImageTag "Combine/Image"
97
99 *combine_view;
100
101 const Image
102 *next;
103
104 Image
105 *combine_image;
106
107 MagickBooleanType
108 status;
109
110 MagickOffsetType
111 progress;
112
113 ssize_t
114 y;
115
116 /*
117 Ensure the image are the same size.
118 */
119 assert(image != (const Image *) NULL);
120 assert(image->signature == MagickCoreSignature);
121 if (IsEventLogging() != MagickFalse)
122 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
123 assert(exception != (ExceptionInfo *) NULL);
124 assert(exception->signature == MagickCoreSignature);
125 for (next=image; next != (Image *) NULL; next=GetNextImageInList(next))
126 {
127 if ((next->columns != image->columns) || (next->rows != image->rows))
128 ThrowImageException(OptionError,"ImagesAreNotTheSameSize");
129 }
130 combine_image=CloneImage(image,0,0,MagickTrue,exception);
131 if (combine_image == (Image *) NULL)
132 return((Image *) NULL);
133 if (SetImageStorageClass(combine_image,DirectClass) == MagickFalse)
134 {
135 InheritException(exception,&combine_image->exception);
136 combine_image=DestroyImage(combine_image);
137 return((Image *) NULL);
138 }
139 if (IssRGBCompatibleColorspace(image->colorspace) != MagickFalse)
140 {
141 if (fabs(image->gamma-1.0) <= MagickEpsilon)
142 (void) SetImageColorspace(combine_image,RGBColorspace);
143 else
144 (void) SetImageColorspace(combine_image,sRGBColorspace);
145 }
146 if ((channel & OpacityChannel) != 0)
147 combine_image->matte=MagickTrue;
148 (void) SetImageBackgroundColor(combine_image);
149 /*
150 Combine images.
151 */
152 status=MagickTrue;
153 progress=0;
154 combine_view=AcquireAuthenticCacheView(combine_image,exception);
155#if defined(MAGICKCORE_OPENMP_SUPPORT)
156 #pragma omp parallel for schedule(static) shared(progress,status) \
157 magick_number_threads(combine_image,combine_image,combine_image->rows,4)
158#endif
159 for (y=0; y < (ssize_t) combine_image->rows; y++)
160 {
162 *image_view;
163
164 const Image
165 *next;
166
168 *pixels;
169
170 const PixelPacket
171 *magick_restrict p;
172
174 *magick_restrict q;
175
176 ssize_t
177 x;
178
179 if (status == MagickFalse)
180 continue;
181 pixels=GetCacheViewAuthenticPixels(combine_view,0,y,combine_image->columns,
182 1,exception);
183 if (pixels == (PixelPacket *) NULL)
184 {
185 status=MagickFalse;
186 continue;
187 }
188 next=image;
189 if (((channel & RedChannel) != 0) && (next != (Image *) NULL))
190 {
191 image_view=AcquireVirtualCacheView(next,exception);
192 p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
193 if (p == (const PixelPacket *) NULL)
194 continue;
195 q=pixels;
196 for (x=0; x < (ssize_t) combine_image->columns; x++)
197 {
198 SetPixelRed(q,ClampToQuantum(GetPixelIntensity(image,p)));
199 p++;
200 q++;
201 }
202 image_view=DestroyCacheView(image_view);
203 next=GetNextImageInList(next);
204 }
205 if (((channel & GreenChannel) != 0) && (next != (Image *) NULL))
206 {
207 image_view=AcquireVirtualCacheView(next,exception);
208 p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
209 if (p == (const PixelPacket *) NULL)
210 continue;
211 q=pixels;
212 for (x=0; x < (ssize_t) combine_image->columns; x++)
213 {
214 SetPixelGreen(q,ClampToQuantum(GetPixelIntensity(image,p)));
215 p++;
216 q++;
217 }
218 image_view=DestroyCacheView(image_view);
219 next=GetNextImageInList(next);
220 }
221 if (((channel & BlueChannel) != 0) && (next != (Image *) NULL))
222 {
223 image_view=AcquireVirtualCacheView(next,exception);
224 p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
225 if (p == (const PixelPacket *) NULL)
226 continue;
227 q=pixels;
228 for (x=0; x < (ssize_t) combine_image->columns; x++)
229 {
230 SetPixelBlue(q,ClampToQuantum(GetPixelIntensity(image,p)));
231 p++;
232 q++;
233 }
234 image_view=DestroyCacheView(image_view);
235 next=GetNextImageInList(next);
236 }
237 if (((channel & OpacityChannel) != 0) && (next != (Image *) NULL))
238 {
239 image_view=AcquireVirtualCacheView(next,exception);
240 p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
241 if (p == (const PixelPacket *) NULL)
242 continue;
243 q=pixels;
244 for (x=0; x < (ssize_t) combine_image->columns; x++)
245 {
246 SetPixelAlpha(q,ClampToQuantum(GetPixelIntensity(image,p)));
247 p++;
248 q++;
249 }
250 image_view=DestroyCacheView(image_view);
251 next=GetNextImageInList(next);
252 }
253 if (((channel & IndexChannel) != 0) &&
254 (image->colorspace == CMYKColorspace) && (next != (Image *) NULL))
255 {
256 IndexPacket
257 *indexes;
258
259 image_view=AcquireVirtualCacheView(next,exception);
260 p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
261 if (p == (const PixelPacket *) NULL)
262 continue;
263 indexes=GetCacheViewAuthenticIndexQueue(combine_view);
264 for (x=0; x < (ssize_t) combine_image->columns; x++)
265 {
266 SetPixelIndex(indexes+x,ClampToQuantum(GetPixelIntensity(image,p)));
267 p++;
268 }
269 image_view=DestroyCacheView(image_view);
270 next=GetNextImageInList(next);
271 }
272 if (SyncCacheViewAuthenticPixels(combine_view,exception) == MagickFalse)
273 status=MagickFalse;
274 if (image->progress_monitor != (MagickProgressMonitor) NULL)
275 {
276 MagickBooleanType
277 proceed;
278
279#if defined(MAGICKCORE_OPENMP_SUPPORT)
280 #pragma omp atomic
281#endif
282 progress++;
283 proceed=SetImageProgress(image,CombineImageTag,progress,
284 combine_image->rows);
285 if (proceed == MagickFalse)
286 status=MagickFalse;
287 }
288 }
289 combine_view=DestroyCacheView(combine_view);
290 if (IsGrayColorspace(combine_image->colorspace) != MagickFalse)
291 (void) TransformImageColorspace(combine_image,sRGBColorspace);
292 if (status == MagickFalse)
293 combine_image=DestroyImage(combine_image);
294 return(combine_image);
295}
296
297/*
298%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
299% %
300% %
301% %
302% G e t I m a g e A l p h a C h a n n e l %
303% %
304% %
305% %
306%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
307%
308% GetImageAlphaChannel() returns MagickFalse if the image alpha channel is
309% not activated. That is, the image is RGB rather than RGBA or CMYK rather
310% than CMYKA.
311%
312% The format of the GetImageAlphaChannel method is:
313%
314% MagickBooleanType GetImageAlphaChannel(const Image *image)
315%
316% A description of each parameter follows:
317%
318% o image: the image.
319%
320*/
321MagickExport MagickBooleanType GetImageAlphaChannel(const Image *image)
322{
323 assert(image != (const Image *) NULL);
324 if (IsEventLogging() != MagickFalse)
325 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
326 assert(image->signature == MagickCoreSignature);
327 return(image->matte);
328}
329
330/*
331%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
332% %
333% %
334% %
335% S e p a r a t e I m a g e C h a n n e l %
336% %
337% %
338% %
339%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
340%
341% SeparateImageChannel() separates a channel from the image and returns it as
342% a grayscale image. A channel is a particular color component of each pixel
343% in the image.
344%
345% The format of the SeparateImageChannel method is:
346%
347% MagickBooleanType SeparateImageChannel(Image *image,
348% const ChannelType channel)
349%
350% A description of each parameter follows:
351%
352% o image: the image.
353%
354% o channel: Identify which channel to extract: RedChannel, GreenChannel,
355% BlueChannel, OpacityChannel, CyanChannel, MagentaChannel,
356% YellowChannel, or BlackChannel.
357%
358*/
359
360MagickExport Image *SeparateImage(const Image *image,const ChannelType channel,
361 ExceptionInfo *exception)
362{
363 Image
364 *separate_image;
365
366 MagickBooleanType
367 status;
368
369 /*
370 Initialize separate image attributes.
371 */
372 assert(image != (Image *) NULL);
373 assert(image->signature == MagickCoreSignature);
374 if (IsEventLogging() != MagickFalse)
375 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
376 assert(exception != (ExceptionInfo *) NULL);
377 assert(exception->signature == MagickCoreSignature);
378 separate_image=CloneImage(image,0,0,MagickTrue,exception);
379 if (separate_image == (Image *) NULL)
380 return((Image *) NULL);
381 status=SeparateImageChannel(separate_image,channel);
382 if (status == MagickFalse)
383 separate_image=DestroyImage(separate_image);
384 return(separate_image);
385}
386
387MagickExport MagickBooleanType SeparateImageChannel(Image *image,
388 const ChannelType channel)
389{
390#define SeparateImageTag "Separate/Image"
391
393 *image_view;
394
396 *exception;
397
398 MagickBooleanType
399 status;
400
401 MagickOffsetType
402 progress;
403
404 ssize_t
405 y;
406
407 assert(image != (Image *) NULL);
408 assert(image->signature == MagickCoreSignature);
409 if (IsEventLogging() != MagickFalse)
410 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
411 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
412 return(MagickFalse);
413 if (channel == GrayChannels)
414 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel);
415 /*
416 Separate image channels.
417 */
418 status=MagickTrue;
419 progress=0;
420 exception=(&image->exception);
421 image_view=AcquireAuthenticCacheView(image,exception);
422#if defined(MAGICKCORE_OPENMP_SUPPORT)
423 #pragma omp parallel for schedule(static) shared(progress,status) \
424 magick_number_threads(image,image,image->rows,2)
425#endif
426 for (y=0; y < (ssize_t) image->rows; y++)
427 {
428 IndexPacket
429 *magick_restrict indexes;
430
432 *magick_restrict q;
433
434 ssize_t
435 x;
436
437 if (status == MagickFalse)
438 continue;
439 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
440 if (q == (PixelPacket *) NULL)
441 {
442 status=MagickFalse;
443 continue;
444 }
445 indexes=GetCacheViewAuthenticIndexQueue(image_view);
446 switch (channel)
447 {
448 case RedChannel:
449 {
450 for (x=0; x < (ssize_t) image->columns; x++)
451 {
452 SetPixelGreen(q,GetPixelRed(q));
453 SetPixelBlue(q,GetPixelRed(q));
454 q++;
455 }
456 break;
457 }
458 case GreenChannel:
459 {
460 for (x=0; x < (ssize_t) image->columns; x++)
461 {
462 SetPixelRed(q,GetPixelGreen(q));
463 SetPixelBlue(q,GetPixelGreen(q));
464 q++;
465 }
466 break;
467 }
468 case BlueChannel:
469 {
470 for (x=0; x < (ssize_t) image->columns; x++)
471 {
472 SetPixelRed(q,GetPixelBlue(q));
473 SetPixelGreen(q,GetPixelBlue(q));
474 q++;
475 }
476 break;
477 }
478 case OpacityChannel:
479 {
480 for (x=0; x < (ssize_t) image->columns; x++)
481 {
482 SetPixelRed(q,GetPixelOpacity(q));
483 SetPixelGreen(q,GetPixelOpacity(q));
484 SetPixelBlue(q,GetPixelOpacity(q));
485 q++;
486 }
487 break;
488 }
489 case BlackChannel:
490 {
491 if ((image->storage_class != PseudoClass) &&
492 (image->colorspace != CMYKColorspace))
493 break;
494 for (x=0; x < (ssize_t) image->columns; x++)
495 {
496 SetPixelRed(q,GetPixelIndex(indexes+x));
497 SetPixelGreen(q,GetPixelIndex(indexes+x));
498 SetPixelBlue(q,GetPixelIndex(indexes+x));
499 q++;
500 }
501 break;
502 }
503 case TrueAlphaChannel:
504 {
505 for (x=0; x < (ssize_t) image->columns; x++)
506 {
507 SetPixelRed(q,GetPixelAlpha(q));
508 SetPixelGreen(q,GetPixelAlpha(q));
509 SetPixelBlue(q,GetPixelAlpha(q));
510 q++;
511 }
512 break;
513 }
514 case GrayChannels:
515 {
516 for (x=0; x < (ssize_t) image->columns; x++)
517 {
518 SetPixelAlpha(q,ClampToQuantum(GetPixelIntensity(image,q)));
519 q++;
520 }
521 break;
522 }
523 default:
524 break;
525 }
526 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
527 status=MagickFalse;
528 if (image->progress_monitor != (MagickProgressMonitor) NULL)
529 {
530 MagickBooleanType
531 proceed;
532
533#if defined(MAGICKCORE_OPENMP_SUPPORT)
534 #pragma omp atomic
535#endif
536 progress++;
537 proceed=SetImageProgress(image,SeparateImageTag,progress,image->rows);
538 if (proceed == MagickFalse)
539 status=MagickFalse;
540 }
541 }
542 image_view=DestroyCacheView(image_view);
543 if (channel != GrayChannels)
544 {
545 image->matte=MagickFalse;
546 (void) SetImageColorspace(image,GRAYColorspace);
547 }
548 return(status);
549}
550
551/*
552%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
553% %
554% %
555% %
556% S e p a r a t e I m a g e s %
557% %
558% %
559% %
560%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
561%
562% SeparateImages() returns a separate grayscale image for each channel
563% specified.
564%
565% The format of the SeparateImages method is:
566%
567% MagickBooleanType SeparateImages(const Image *image,
568% const ChannelType channel,ExceptionInfo *exception)
569%
570% A description of each parameter follows:
571%
572% o image: the image.
573%
574% o channel: Identify which channels to extract: RedChannel, GreenChannel,
575% BlueChannel, OpacityChannel, CyanChannel, MagentaChannel,
576% YellowChannel, or BlackChannel.
577%
578% o exception: return any errors or warnings in this structure.
579%
580*/
581MagickExport Image *SeparateImages(const Image *image,const ChannelType channel,
582 ExceptionInfo *exception)
583{
584 Image
585 *images,
586 *separate_image;
587
588 assert(image != (Image *) NULL);
589 assert(image->signature == MagickCoreSignature);
590 if (IsEventLogging() != MagickFalse)
591 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
592 images=NewImageList();
593 if ((channel & RedChannel) != 0)
594 {
595 separate_image=CloneImage(image,0,0,MagickTrue,exception);
596 (void) SeparateImageChannel(separate_image,RedChannel);
597 AppendImageToList(&images,separate_image);
598 }
599 if ((channel & GreenChannel) != 0)
600 {
601 separate_image=CloneImage(image,0,0,MagickTrue,exception);
602 (void) SeparateImageChannel(separate_image,GreenChannel);
603 AppendImageToList(&images,separate_image);
604 }
605 if ((channel & BlueChannel) != 0)
606 {
607 separate_image=CloneImage(image,0,0,MagickTrue,exception);
608 (void) SeparateImageChannel(separate_image,BlueChannel);
609 AppendImageToList(&images,separate_image);
610 }
611 if (((channel & BlackChannel) != 0) && (image->colorspace == CMYKColorspace))
612 {
613 separate_image=CloneImage(image,0,0,MagickTrue,exception);
614 (void) SeparateImageChannel(separate_image,BlackChannel);
615 AppendImageToList(&images,separate_image);
616 }
617 if ((channel & AlphaChannel) != 0)
618 {
619 separate_image=CloneImage(image,0,0,MagickTrue,exception);
620 (void) SeparateImageChannel(separate_image,TrueAlphaChannel);
621 AppendImageToList(&images,separate_image);
622 }
623 return(images);
624}
625
626/*
627%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
628% %
629% %
630% %
631% S e t I m a g e A l p h a C h a n n e l %
632% %
633% %
634% %
635%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
636%
637% SetImageAlphaChannel() activates, deactivates, resets, or sets the alpha
638% channel.
639%
640% The format of the SetImageAlphaChannel method is:
641%
642% MagickBooleanType SetImageAlphaChannel(Image *image,
643% const AlphaChannelType alpha_type)
644%
645% A description of each parameter follows:
646%
647% o image: the image.
648%
649% o alpha_type: The alpha channel type: ActivateAlphaChannel,
650% AssociateAlphaChannel, CopyAlphaChannel, Disassociate,
651% DeactivateAlphaChannel, ExtractAlphaChannel, OpaqueAlphaChannel,
652% ResetAlphaChannel, SetAlphaChannel, ShapeAlphaChannel, and
653% TransparentAlphaChannel.
654%
655*/
656MagickExport MagickBooleanType SetImageAlphaChannel(Image *image,
657 const AlphaChannelType alpha_type)
658{
660 *image_view;
661
663 *exception;
664
665 MagickBooleanType
666 status;
667
668 ssize_t
669 y;
670
671 assert(image != (Image *) NULL);
672 if (IsEventLogging() != MagickFalse)
673 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
674 assert(image->signature == MagickCoreSignature);
675 exception=(&image->exception);
676 status=MagickTrue;
677 switch (alpha_type)
678 {
679 case ActivateAlphaChannel:
680 {
681 if (image->matte == MagickTrue)
682 return(status);
683 image->matte=MagickTrue;
684 break;
685 }
686 case AssociateAlphaChannel:
687 {
688 /*
689 Associate alpha.
690 */
691 status=SetImageStorageClass(image,DirectClass);
692 if (status == MagickFalse)
693 break;
694 image_view=AcquireAuthenticCacheView(image,exception);
695 #if defined(MAGICKCORE_OPENMP_SUPPORT)
696 #pragma omp parallel for schedule(static) shared(status) \
697 magick_number_threads(image,image,image->rows,2)
698 #endif
699 for (y=0; y < (ssize_t) image->rows; y++)
700 {
702 *magick_restrict q;
703
704 ssize_t
705 x;
706
707 if (status == MagickFalse)
708 continue;
709 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
710 exception);
711 if (q == (PixelPacket *) NULL)
712 {
713 status=MagickFalse;
714 continue;
715 }
716 for (x=0; x < (ssize_t) image->columns; x++)
717 {
718 double
719 gamma;
720
721 gamma=QuantumScale*(double) GetPixelAlpha(q);
722 SetPixelRed(q,ClampToQuantum(gamma*(double) GetPixelRed(q)));
723 SetPixelGreen(q,ClampToQuantum(gamma*(double) GetPixelGreen(q)));
724 SetPixelBlue(q,ClampToQuantum(gamma*(double) GetPixelBlue(q)));
725 q++;
726 }
727 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
728 status=MagickFalse;
729 }
730 image_view=DestroyCacheView(image_view);
731 image->matte=MagickFalse;
732 break;
733 }
734 case BackgroundAlphaChannel:
735 {
736 IndexPacket
737 index;
738
739 MagickBooleanType
740 status;
741
743 background;
744
746 pixel;
747
748 /*
749 Set transparent pixels to background color.
750 */
751 if (image->matte == MagickFalse)
752 break;
753 status=SetImageStorageClass(image,DirectClass);
754 if (status == MagickFalse)
755 break;
756 GetMagickPixelPacket(image,&background);
757 SetMagickPixelPacket(image,&image->background_color,(const IndexPacket *)
758 NULL,&background);
759 if (image->colorspace == CMYKColorspace)
760 ConvertRGBToCMYK(&background);
761 index=0;
762 SetPixelPacket(image,&background,&pixel,&index);
763 status=MagickTrue;
764 exception=(&image->exception);
765 image_view=AcquireAuthenticCacheView(image,exception);
766 #if defined(MAGICKCORE_OPENMP_SUPPORT)
767 #pragma omp parallel for schedule(static) shared(status) \
768 magick_number_threads(image,image,image->rows,2)
769 #endif
770 for (y=0; y < (ssize_t) image->rows; y++)
771 {
772 IndexPacket
773 *magick_restrict indexes;
774
776 *magick_restrict q;
777
778 ssize_t
779 x;
780
781 if (status == MagickFalse)
782 continue;
783 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
784 exception);
785 if (q == (PixelPacket *) NULL)
786 {
787 status=MagickFalse;
788 continue;
789 }
790 for (x=0; x < (ssize_t) image->columns; x++)
791 {
792 if (q->opacity == TransparentOpacity)
793 {
794 SetPixelRed(q,pixel.red);
795 SetPixelGreen(q,pixel.green);
796 SetPixelBlue(q,pixel.blue);
797 }
798 q++;
799 }
800 if (image->colorspace == CMYKColorspace)
801 {
802 indexes=GetCacheViewAuthenticIndexQueue(image_view);
803 for (x=0; x < (ssize_t) image->columns; x++)
804 SetPixelIndex(indexes+x,index);
805 }
806 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
807 status=MagickFalse;
808 }
809 image_view=DestroyCacheView(image_view);
810 return(status);
811 }
812 case CopyAlphaChannel:
813 case ShapeAlphaChannel:
814 {
815 /*
816 Special usage case for SeparateImageChannel(): copy grayscale color to
817 the alpha channel.
818 */
819 status=SeparateImageChannel(image,GrayChannels);
820 image->matte=MagickTrue; /* make sure transparency is now on! */
821 if (alpha_type == ShapeAlphaChannel)
822 {
824 background;
825
826 /*
827 Reset all color channels to background color.
828 */
829 GetMagickPixelPacket(image,&background);
830 SetMagickPixelPacket(image,&(image->background_color),(IndexPacket *)
831 NULL,&background);
832 (void) LevelColorsImage(image,&background,&background,MagickTrue);
833 }
834 break;
835 }
836 case DeactivateAlphaChannel:
837 {
838 if (image->matte == MagickFalse)
839 return(status);
840 image->matte=MagickFalse;
841 break;
842 }
843 case DisassociateAlphaChannel:
844 {
845 status=SetImageStorageClass(image,DirectClass);
846 if (status == MagickFalse)
847 break;
848 image->matte=MagickTrue;
849 image_view=AcquireAuthenticCacheView(image,exception);
850 #if defined(MAGICKCORE_OPENMP_SUPPORT)
851 #pragma omp parallel for schedule(static) shared(status) \
852 magick_number_threads(image,image,image->rows,2)
853 #endif
854 for (y=0; y < (ssize_t) image->rows; y++)
855 {
857 *magick_restrict q;
858
859 ssize_t
860 x;
861
862 if (status == MagickFalse)
863 continue;
864 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
865 exception);
866 if (q == (PixelPacket *) NULL)
867 {
868 status=MagickFalse;
869 continue;
870 }
871 for (x=0; x < (ssize_t) image->columns; x++)
872 {
873 double
874 alpha,
875 gamma;
876
877 alpha=QuantumScale*(double) GetPixelAlpha(q);
878 gamma=PerceptibleReciprocal(alpha);
879 SetPixelRed(q,ClampToQuantum(gamma*(double) GetPixelRed(q)));
880 SetPixelGreen(q,ClampToQuantum(gamma*(double) GetPixelGreen(q)));
881 SetPixelBlue(q,ClampToQuantum(gamma*(double) GetPixelBlue(q)));
882 q++;
883 }
884 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
885 status=MagickFalse;
886 }
887 image_view=DestroyCacheView(image_view);
888 image->matte=MagickFalse;
889 break;
890 }
891 case ExtractAlphaChannel:
892 {
893 status=SeparateImageChannel(image,TrueAlphaChannel);
894 image->matte=MagickFalse;
895 break;
896 }
897 case OffIfOpaqueAlphaChannel:
898 {
899 MagickBooleanType
900 opaque = MagickTrue;
901
902 /*
903 Remove opaque alpha channel.
904 */
905 image_view=AcquireVirtualCacheView(image,exception);
906 #if defined(MAGICKCORE_OPENMP_SUPPORT)
907 #pragma omp parallel for schedule(static) shared(opaque,status) \
908 magick_number_threads(image,image,image->rows,2)
909 #endif
910 for (y=0; y < (ssize_t) image->rows; y++)
911 {
912 const PixelPacket
913 *magick_restrict p;
914
915 ssize_t
916 x;
917
918 if ((status == MagickFalse) || (opaque == MagickFalse))
919 continue;
920 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
921 if (p == (const PixelPacket *) NULL)
922 {
923 status=MagickFalse;
924 continue;
925 }
926 for (x=0; x < (ssize_t) image->columns; x++)
927 {
928 if (GetPixelOpacity(p) != OpaqueOpacity)
929 {
930 opaque=MagickFalse;
931 break;
932 }
933 p++;
934 }
935 }
936 image_view=DestroyCacheView(image_view);
937 if (opaque != MagickFalse)
938 image->matte=MagickFalse;
939 break;
940 }
941 case ResetAlphaChannel: /* deprecated */
942 case RemoveAlphaChannel:
943 case FlattenAlphaChannel:
944 {
945 IndexPacket
946 index;
947
949 background;
950
952 pixel;
953
954 /*
955 Flatten image pixels over the background pixels.
956 */
957 if (image->matte == MagickFalse)
958 break;
959 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
960 break;
961 GetMagickPixelPacket(image,&background);
962 SetMagickPixelPacket(image,&image->background_color,(const IndexPacket *)
963 NULL,&background);
964 if (image->colorspace == CMYKColorspace)
965 ConvertRGBToCMYK(&background);
966 (void) memset(&pixel,0,sizeof(pixel));
967 index=0;
968 SetPixelPacket(image,&background,&pixel,&index);
969 image_view=AcquireAuthenticCacheView(image,exception);
970 #if defined(MAGICKCORE_OPENMP_SUPPORT)
971 #pragma omp parallel for schedule(static) shared(status) \
972 magick_number_threads(image,image,image->rows,2)
973 #endif
974 for (y=0; y < (ssize_t) image->rows; y++)
975 {
976 IndexPacket
977 *magick_restrict indexes;
978
980 *magick_restrict q;
981
982 ssize_t
983 x;
984
985 if (status == MagickFalse)
986 continue;
987 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
988 exception);
989 if (q == (PixelPacket *) NULL)
990 {
991 status=MagickFalse;
992 continue;
993 }
994 for (x=0; x < (ssize_t) image->columns; x++)
995 {
996 double
997 gamma,
998 opacity;
999
1000 gamma=1.0-QuantumScale*QuantumScale*(double) q->opacity*(double)
1001 pixel.opacity;
1002 opacity=(double) QuantumRange*(1.0-gamma);
1003 gamma=PerceptibleReciprocal(gamma);
1004 q->red=ClampToQuantum(gamma*MagickOver_((MagickRealType) q->red,
1005 (MagickRealType) q->opacity,(MagickRealType) pixel.red,
1006 (MagickRealType) pixel.opacity));
1007 q->green=ClampToQuantum(gamma*MagickOver_((MagickRealType) q->green,
1008 (MagickRealType) q->opacity,(MagickRealType) pixel.green,
1009 (MagickRealType) pixel.opacity));
1010 q->blue=ClampToQuantum(gamma*MagickOver_((MagickRealType) q->blue,
1011 (MagickRealType) q->opacity,(MagickRealType) pixel.blue,
1012 (MagickRealType) pixel.opacity));
1013 q->opacity=ClampToQuantum(opacity);
1014 q++;
1015 }
1016 if (image->colorspace == CMYKColorspace)
1017 {
1018 indexes=GetCacheViewAuthenticIndexQueue(image_view);
1019 for (x=0; x < (ssize_t) image->columns; x++)
1020 SetPixelIndex(indexes+x,index);
1021 }
1022 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
1023 status=MagickFalse;
1024 }
1025 image_view=DestroyCacheView(image_view);
1026 return(status);
1027 }
1028 case OpaqueAlphaChannel:
1029 {
1030 status=SetImageOpacity(image,OpaqueOpacity);
1031 break;
1032 }
1033 case SetAlphaChannel:
1034 {
1035 if (image->matte == MagickFalse)
1036 status=SetImageOpacity(image,OpaqueOpacity);
1037 break;
1038 }
1039 case TransparentAlphaChannel:
1040 {
1041 status=SetImageOpacity(image,TransparentOpacity);
1042 break;
1043 }
1044 case UndefinedAlphaChannel:
1045 break;
1046 }
1047 if (status == MagickFalse)
1048 return(status);
1049 return(SyncImagePixelCache(image,&image->exception));
1050}