MagickCore 6.9.12-98
Convert, Edit, Or Compose Bitmap Images
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 for (y=0; y < (ssize_t) combine_image->rows; y++)
156 {
158 *image_view;
159
160 const Image
161 *next;
162
164 *pixels;
165
166 const PixelPacket
167 *magick_restrict p;
168
170 *magick_restrict q;
171
172 ssize_t
173 x;
174
175 if (status == MagickFalse)
176 continue;
177 pixels=GetCacheViewAuthenticPixels(combine_view,0,y,combine_image->columns,
178 1,exception);
179 if (pixels == (PixelPacket *) NULL)
180 {
181 status=MagickFalse;
182 continue;
183 }
184 next=image;
185 if (((channel & RedChannel) != 0) && (next != (Image *) NULL))
186 {
187 image_view=AcquireVirtualCacheView(next,exception);
188 p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
189 if (p == (const PixelPacket *) NULL)
190 continue;
191 q=pixels;
192 for (x=0; x < (ssize_t) combine_image->columns; x++)
193 {
194 SetPixelRed(q,ClampToQuantum(GetPixelIntensity(image,p)));
195 p++;
196 q++;
197 }
198 image_view=DestroyCacheView(image_view);
199 next=GetNextImageInList(next);
200 }
201 if (((channel & GreenChannel) != 0) && (next != (Image *) NULL))
202 {
203 image_view=AcquireVirtualCacheView(next,exception);
204 p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
205 if (p == (const PixelPacket *) NULL)
206 continue;
207 q=pixels;
208 for (x=0; x < (ssize_t) combine_image->columns; x++)
209 {
210 SetPixelGreen(q,ClampToQuantum(GetPixelIntensity(image,p)));
211 p++;
212 q++;
213 }
214 image_view=DestroyCacheView(image_view);
215 next=GetNextImageInList(next);
216 }
217 if (((channel & BlueChannel) != 0) && (next != (Image *) NULL))
218 {
219 image_view=AcquireVirtualCacheView(next,exception);
220 p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
221 if (p == (const PixelPacket *) NULL)
222 continue;
223 q=pixels;
224 for (x=0; x < (ssize_t) combine_image->columns; x++)
225 {
226 SetPixelBlue(q,ClampToQuantum(GetPixelIntensity(image,p)));
227 p++;
228 q++;
229 }
230 image_view=DestroyCacheView(image_view);
231 next=GetNextImageInList(next);
232 }
233 if (((channel & OpacityChannel) != 0) && (next != (Image *) NULL))
234 {
235 image_view=AcquireVirtualCacheView(next,exception);
236 p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
237 if (p == (const PixelPacket *) NULL)
238 continue;
239 q=pixels;
240 for (x=0; x < (ssize_t) combine_image->columns; x++)
241 {
242 SetPixelAlpha(q,ClampToQuantum(GetPixelIntensity(image,p)));
243 p++;
244 q++;
245 }
246 image_view=DestroyCacheView(image_view);
247 next=GetNextImageInList(next);
248 }
249 if (((channel & IndexChannel) != 0) &&
250 (image->colorspace == CMYKColorspace) && (next != (Image *) NULL))
251 {
252 IndexPacket
253 *indexes;
254
255 image_view=AcquireVirtualCacheView(next,exception);
256 p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
257 if (p == (const PixelPacket *) NULL)
258 continue;
259 indexes=GetCacheViewAuthenticIndexQueue(combine_view);
260 for (x=0; x < (ssize_t) combine_image->columns; x++)
261 {
262 SetPixelIndex(indexes+x,ClampToQuantum(GetPixelIntensity(image,p)));
263 p++;
264 }
265 image_view=DestroyCacheView(image_view);
266 next=GetNextImageInList(next);
267 }
268 if (SyncCacheViewAuthenticPixels(combine_view,exception) == MagickFalse)
269 status=MagickFalse;
270 if (image->progress_monitor != (MagickProgressMonitor) NULL)
271 {
272 MagickBooleanType
273 proceed;
274
275#if defined(MAGICKCORE_OPENMP_SUPPORT)
276 #pragma omp atomic
277#endif
278 progress++;
279 proceed=SetImageProgress(image,CombineImageTag,progress,
280 combine_image->rows);
281 if (proceed == MagickFalse)
282 status=MagickFalse;
283 }
284 }
285 combine_view=DestroyCacheView(combine_view);
286 if (IsGrayColorspace(combine_image->colorspace) != MagickFalse)
287 (void) TransformImageColorspace(combine_image,sRGBColorspace);
288 if (status == MagickFalse)
289 combine_image=DestroyImage(combine_image);
290 return(combine_image);
291}
292
293/*
294%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
295% %
296% %
297% %
298% G e t I m a g e A l p h a C h a n n e l %
299% %
300% %
301% %
302%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
303%
304% GetImageAlphaChannel() returns MagickFalse if the image alpha channel is
305% not activated. That is, the image is RGB rather than RGBA or CMYK rather
306% than CMYKA.
307%
308% The format of the GetImageAlphaChannel method is:
309%
310% MagickBooleanType GetImageAlphaChannel(const Image *image)
311%
312% A description of each parameter follows:
313%
314% o image: the image.
315%
316*/
317MagickExport MagickBooleanType GetImageAlphaChannel(const Image *image)
318{
319 assert(image != (const Image *) NULL);
320 if (IsEventLogging() != MagickFalse)
321 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
322 assert(image->signature == MagickCoreSignature);
323 return(image->matte);
324}
325
326/*
327%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
328% %
329% %
330% %
331% S e p a r a t e I m a g e C h a n n e l %
332% %
333% %
334% %
335%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
336%
337% SeparateImageChannel() separates a channel from the image and returns it as
338% a grayscale image. A channel is a particular color component of each pixel
339% in the image.
340%
341% The format of the SeparateImageChannel method is:
342%
343% MagickBooleanType SeparateImageChannel(Image *image,
344% const ChannelType channel)
345%
346% A description of each parameter follows:
347%
348% o image: the image.
349%
350% o channel: Identify which channel to extract: RedChannel, GreenChannel,
351% BlueChannel, OpacityChannel, CyanChannel, MagentaChannel,
352% YellowChannel, or BlackChannel.
353%
354*/
355
356MagickExport Image *SeparateImage(const Image *image,const ChannelType channel,
357 ExceptionInfo *exception)
358{
359 Image
360 *separate_image;
361
362 MagickBooleanType
363 status;
364
365 /*
366 Initialize separate image attributes.
367 */
368 assert(image != (Image *) NULL);
369 assert(image->signature == MagickCoreSignature);
370 if (IsEventLogging() != MagickFalse)
371 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
372 assert(exception != (ExceptionInfo *) NULL);
373 assert(exception->signature == MagickCoreSignature);
374 separate_image=CloneImage(image,0,0,MagickTrue,exception);
375 if (separate_image == (Image *) NULL)
376 return((Image *) NULL);
377 status=SeparateImageChannel(separate_image,channel);
378 if (status == MagickFalse)
379 separate_image=DestroyImage(separate_image);
380 return(separate_image);
381}
382
383MagickExport MagickBooleanType SeparateImageChannel(Image *image,
384 const ChannelType channel)
385{
386#define SeparateImageTag "Separate/Image"
387
389 *image_view;
390
392 *exception;
393
394 MagickBooleanType
395 status;
396
397 MagickOffsetType
398 progress;
399
400 ssize_t
401 y;
402
403 assert(image != (Image *) NULL);
404 assert(image->signature == MagickCoreSignature);
405 if (IsEventLogging() != MagickFalse)
406 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
407 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
408 return(MagickFalse);
409 if (channel == GrayChannels)
410 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel);
411 /*
412 Separate image channels.
413 */
414 status=MagickTrue;
415 progress=0;
416 exception=(&image->exception);
417 image_view=AcquireAuthenticCacheView(image,exception);
418#if defined(MAGICKCORE_OPENMP_SUPPORT)
419 #pragma omp parallel for schedule(static) shared(progress,status) \
420 magick_number_threads(image,image,image->rows,1)
421#endif
422 for (y=0; y < (ssize_t) image->rows; y++)
423 {
424 IndexPacket
425 *magick_restrict indexes;
426
428 *magick_restrict q;
429
430 ssize_t
431 x;
432
433 if (status == MagickFalse)
434 continue;
435 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
436 if (q == (PixelPacket *) NULL)
437 {
438 status=MagickFalse;
439 continue;
440 }
441 indexes=GetCacheViewAuthenticIndexQueue(image_view);
442 switch (channel)
443 {
444 case RedChannel:
445 {
446 for (x=0; x < (ssize_t) image->columns; x++)
447 {
448 SetPixelGreen(q,GetPixelRed(q));
449 SetPixelBlue(q,GetPixelRed(q));
450 q++;
451 }
452 break;
453 }
454 case GreenChannel:
455 {
456 for (x=0; x < (ssize_t) image->columns; x++)
457 {
458 SetPixelRed(q,GetPixelGreen(q));
459 SetPixelBlue(q,GetPixelGreen(q));
460 q++;
461 }
462 break;
463 }
464 case BlueChannel:
465 {
466 for (x=0; x < (ssize_t) image->columns; x++)
467 {
468 SetPixelRed(q,GetPixelBlue(q));
469 SetPixelGreen(q,GetPixelBlue(q));
470 q++;
471 }
472 break;
473 }
474 case OpacityChannel:
475 {
476 for (x=0; x < (ssize_t) image->columns; x++)
477 {
478 SetPixelRed(q,GetPixelOpacity(q));
479 SetPixelGreen(q,GetPixelOpacity(q));
480 SetPixelBlue(q,GetPixelOpacity(q));
481 q++;
482 }
483 break;
484 }
485 case BlackChannel:
486 {
487 if ((image->storage_class != PseudoClass) &&
488 (image->colorspace != CMYKColorspace))
489 break;
490 for (x=0; x < (ssize_t) image->columns; x++)
491 {
492 SetPixelRed(q,GetPixelIndex(indexes+x));
493 SetPixelGreen(q,GetPixelIndex(indexes+x));
494 SetPixelBlue(q,GetPixelIndex(indexes+x));
495 q++;
496 }
497 break;
498 }
499 case TrueAlphaChannel:
500 {
501 for (x=0; x < (ssize_t) image->columns; x++)
502 {
503 SetPixelRed(q,GetPixelAlpha(q));
504 SetPixelGreen(q,GetPixelAlpha(q));
505 SetPixelBlue(q,GetPixelAlpha(q));
506 q++;
507 }
508 break;
509 }
510 case GrayChannels:
511 {
512 for (x=0; x < (ssize_t) image->columns; x++)
513 {
514 SetPixelAlpha(q,ClampToQuantum(GetPixelIntensity(image,q)));
515 q++;
516 }
517 break;
518 }
519 default:
520 break;
521 }
522 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
523 status=MagickFalse;
524 if (image->progress_monitor != (MagickProgressMonitor) NULL)
525 {
526 MagickBooleanType
527 proceed;
528
529#if defined(MAGICKCORE_OPENMP_SUPPORT)
530 #pragma omp atomic
531#endif
532 progress++;
533 proceed=SetImageProgress(image,SeparateImageTag,progress,image->rows);
534 if (proceed == MagickFalse)
535 status=MagickFalse;
536 }
537 }
538 image_view=DestroyCacheView(image_view);
539 if (channel != GrayChannels)
540 {
541 image->matte=MagickFalse;
542 (void) SetImageColorspace(image,GRAYColorspace);
543 }
544 return(status);
545}
546
547/*
548%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
549% %
550% %
551% %
552% S e p a r a t e I m a g e s %
553% %
554% %
555% %
556%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
557%
558% SeparateImages() returns a separate grayscale image for each channel
559% specified.
560%
561% The format of the SeparateImages method is:
562%
563% MagickBooleanType SeparateImages(const Image *image,
564% const ChannelType channel,ExceptionInfo *exception)
565%
566% A description of each parameter follows:
567%
568% o image: the image.
569%
570% o channel: Identify which channels to extract: RedChannel, GreenChannel,
571% BlueChannel, OpacityChannel, CyanChannel, MagentaChannel,
572% YellowChannel, or BlackChannel.
573%
574% o exception: return any errors or warnings in this structure.
575%
576*/
577MagickExport Image *SeparateImages(const Image *image,const ChannelType channel,
578 ExceptionInfo *exception)
579{
580 Image
581 *images,
582 *separate_image;
583
584 assert(image != (Image *) NULL);
585 assert(image->signature == MagickCoreSignature);
586 if (IsEventLogging() != MagickFalse)
587 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
588 images=NewImageList();
589 if ((channel & RedChannel) != 0)
590 {
591 separate_image=CloneImage(image,0,0,MagickTrue,exception);
592 (void) SeparateImageChannel(separate_image,RedChannel);
593 AppendImageToList(&images,separate_image);
594 }
595 if ((channel & GreenChannel) != 0)
596 {
597 separate_image=CloneImage(image,0,0,MagickTrue,exception);
598 (void) SeparateImageChannel(separate_image,GreenChannel);
599 AppendImageToList(&images,separate_image);
600 }
601 if ((channel & BlueChannel) != 0)
602 {
603 separate_image=CloneImage(image,0,0,MagickTrue,exception);
604 (void) SeparateImageChannel(separate_image,BlueChannel);
605 AppendImageToList(&images,separate_image);
606 }
607 if (((channel & BlackChannel) != 0) && (image->colorspace == CMYKColorspace))
608 {
609 separate_image=CloneImage(image,0,0,MagickTrue,exception);
610 (void) SeparateImageChannel(separate_image,BlackChannel);
611 AppendImageToList(&images,separate_image);
612 }
613 if ((channel & AlphaChannel) != 0)
614 {
615 separate_image=CloneImage(image,0,0,MagickTrue,exception);
616 (void) SeparateImageChannel(separate_image,TrueAlphaChannel);
617 AppendImageToList(&images,separate_image);
618 }
619 return(images);
620}
621
622/*
623%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
624% %
625% %
626% %
627% S e t I m a g e A l p h a C h a n n e l %
628% %
629% %
630% %
631%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
632%
633% SetImageAlphaChannel() activates, deactivates, resets, or sets the alpha
634% channel.
635%
636% The format of the SetImageAlphaChannel method is:
637%
638% MagickBooleanType SetImageAlphaChannel(Image *image,
639% const AlphaChannelType alpha_type)
640%
641% A description of each parameter follows:
642%
643% o image: the image.
644%
645% o alpha_type: The alpha channel type: ActivateAlphaChannel,
646% AssociateAlphaChannel, CopyAlphaChannel, Disassociate,
647% DeactivateAlphaChannel, ExtractAlphaChannel, OpaqueAlphaChannel,
648% ResetAlphaChannel, SetAlphaChannel, ShapeAlphaChannel, and
649% TransparentAlphaChannel.
650%
651*/
652MagickExport MagickBooleanType SetImageAlphaChannel(Image *image,
653 const AlphaChannelType alpha_type)
654{
656 *image_view;
657
659 *exception;
660
661 MagickBooleanType
662 status;
663
664 ssize_t
665 y;
666
667 assert(image != (Image *) NULL);
668 if (IsEventLogging() != MagickFalse)
669 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
670 assert(image->signature == MagickCoreSignature);
671 exception=(&image->exception);
672 status=MagickTrue;
673 switch (alpha_type)
674 {
675 case ActivateAlphaChannel:
676 {
677 if (image->matte == MagickTrue)
678 return(status);
679 image->matte=MagickTrue;
680 break;
681 }
682 case AssociateAlphaChannel:
683 {
684 /*
685 Associate alpha.
686 */
687 status=SetImageStorageClass(image,DirectClass);
688 if (status == MagickFalse)
689 break;
690 image_view=AcquireAuthenticCacheView(image,exception);
691 #if defined(MAGICKCORE_OPENMP_SUPPORT)
692 #pragma omp parallel for schedule(static) shared(status) \
693 magick_number_threads(image,image,image->rows,1)
694 #endif
695 for (y=0; y < (ssize_t) image->rows; y++)
696 {
698 *magick_restrict q;
699
700 ssize_t
701 x;
702
703 if (status == MagickFalse)
704 continue;
705 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
706 exception);
707 if (q == (PixelPacket *) NULL)
708 {
709 status=MagickFalse;
710 continue;
711 }
712 for (x=0; x < (ssize_t) image->columns; x++)
713 {
714 double
715 gamma;
716
717 gamma=QuantumScale*(double) GetPixelAlpha(q);
718 SetPixelRed(q,ClampToQuantum(gamma*(double) GetPixelRed(q)));
719 SetPixelGreen(q,ClampToQuantum(gamma*(double) GetPixelGreen(q)));
720 SetPixelBlue(q,ClampToQuantum(gamma*(double) GetPixelBlue(q)));
721 q++;
722 }
723 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
724 status=MagickFalse;
725 }
726 image_view=DestroyCacheView(image_view);
727 image->matte=MagickFalse;
728 break;
729 }
730 case BackgroundAlphaChannel:
731 {
732 IndexPacket
733 index;
734
735 MagickBooleanType
736 status;
737
739 background;
740
742 pixel;
743
744 /*
745 Set transparent pixels to background color.
746 */
747 if (image->matte == MagickFalse)
748 break;
749 status=SetImageStorageClass(image,DirectClass);
750 if (status == MagickFalse)
751 break;
752 GetMagickPixelPacket(image,&background);
753 SetMagickPixelPacket(image,&image->background_color,(const IndexPacket *)
754 NULL,&background);
755 if (image->colorspace == CMYKColorspace)
756 ConvertRGBToCMYK(&background);
757 index=0;
758 SetPixelPacket(image,&background,&pixel,&index);
759 status=MagickTrue;
760 exception=(&image->exception);
761 image_view=AcquireAuthenticCacheView(image,exception);
762 #if defined(MAGICKCORE_OPENMP_SUPPORT)
763 #pragma omp parallel for schedule(static) shared(status) \
764 magick_number_threads(image,image,image->rows,1)
765 #endif
766 for (y=0; y < (ssize_t) image->rows; y++)
767 {
768 IndexPacket
769 *magick_restrict indexes;
770
772 *magick_restrict q;
773
774 ssize_t
775 x;
776
777 if (status == MagickFalse)
778 continue;
779 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
780 exception);
781 if (q == (PixelPacket *) NULL)
782 {
783 status=MagickFalse;
784 continue;
785 }
786 for (x=0; x < (ssize_t) image->columns; x++)
787 {
788 if (q->opacity == TransparentOpacity)
789 {
790 SetPixelRed(q,pixel.red);
791 SetPixelGreen(q,pixel.green);
792 SetPixelBlue(q,pixel.blue);
793 }
794 q++;
795 }
796 if (image->colorspace == CMYKColorspace)
797 {
798 indexes=GetCacheViewAuthenticIndexQueue(image_view);
799 for (x=0; x < (ssize_t) image->columns; x++)
800 SetPixelIndex(indexes+x,index);
801 }
802 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
803 status=MagickFalse;
804 }
805 image_view=DestroyCacheView(image_view);
806 return(status);
807 }
808 case CopyAlphaChannel:
809 case ShapeAlphaChannel:
810 {
811 /*
812 Special usage case for SeparateImageChannel(): copy grayscale color to
813 the alpha channel.
814 */
815 status=SeparateImageChannel(image,GrayChannels);
816 image->matte=MagickTrue; /* make sure transparency is now on! */
817 if (alpha_type == ShapeAlphaChannel)
818 {
820 background;
821
822 /*
823 Reset all color channels to background color.
824 */
825 GetMagickPixelPacket(image,&background);
826 SetMagickPixelPacket(image,&(image->background_color),(IndexPacket *)
827 NULL,&background);
828 (void) LevelColorsImage(image,&background,&background,MagickTrue);
829 }
830 break;
831 }
832 case DeactivateAlphaChannel:
833 {
834 if (image->matte == MagickFalse)
835 return(status);
836 image->matte=MagickFalse;
837 break;
838 }
839 case DisassociateAlphaChannel:
840 {
841 status=SetImageStorageClass(image,DirectClass);
842 if (status == MagickFalse)
843 break;
844 image->matte=MagickTrue;
845 image_view=AcquireAuthenticCacheView(image,exception);
846 #if defined(MAGICKCORE_OPENMP_SUPPORT)
847 #pragma omp parallel for schedule(static) shared(status) \
848 magick_number_threads(image,image,image->rows,1)
849 #endif
850 for (y=0; y < (ssize_t) image->rows; y++)
851 {
853 *magick_restrict q;
854
855 ssize_t
856 x;
857
858 if (status == MagickFalse)
859 continue;
860 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
861 exception);
862 if (q == (PixelPacket *) NULL)
863 {
864 status=MagickFalse;
865 continue;
866 }
867 for (x=0; x < (ssize_t) image->columns; x++)
868 {
869 double
870 alpha,
871 gamma;
872
873 alpha=QuantumScale*(double) GetPixelAlpha(q);
874 gamma=PerceptibleReciprocal(alpha);
875 SetPixelRed(q,ClampToQuantum(gamma*(double) GetPixelRed(q)));
876 SetPixelGreen(q,ClampToQuantum(gamma*(double) GetPixelGreen(q)));
877 SetPixelBlue(q,ClampToQuantum(gamma*(double) GetPixelBlue(q)));
878 q++;
879 }
880 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
881 status=MagickFalse;
882 }
883 image_view=DestroyCacheView(image_view);
884 image->matte=MagickFalse;
885 break;
886 }
887 case ExtractAlphaChannel:
888 {
889 status=SeparateImageChannel(image,TrueAlphaChannel);
890 image->matte=MagickFalse;
891 break;
892 }
893 case RemoveAlphaChannel:
894 case FlattenAlphaChannel:
895 {
896 IndexPacket
897 index;
898
900 background;
901
903 pixel;
904
905 /*
906 Flatten image pixels over the background pixels.
907 */
908 if (image->matte == MagickFalse)
909 break;
910 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
911 break;
912 GetMagickPixelPacket(image,&background);
913 SetMagickPixelPacket(image,&image->background_color,(const IndexPacket *)
914 NULL,&background);
915 if (image->colorspace == CMYKColorspace)
916 ConvertRGBToCMYK(&background);
917 (void) memset(&pixel,0,sizeof(pixel));
918 index=0;
919 SetPixelPacket(image,&background,&pixel,&index);
920 image_view=AcquireAuthenticCacheView(image,exception);
921 #if defined(MAGICKCORE_OPENMP_SUPPORT)
922 #pragma omp parallel for schedule(static) shared(status) \
923 magick_number_threads(image,image,image->rows,1)
924 #endif
925 for (y=0; y < (ssize_t) image->rows; y++)
926 {
927 IndexPacket
928 *magick_restrict indexes;
929
931 *magick_restrict q;
932
933 ssize_t
934 x;
935
936 if (status == MagickFalse)
937 continue;
938 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
939 exception);
940 if (q == (PixelPacket *) NULL)
941 {
942 status=MagickFalse;
943 continue;
944 }
945 for (x=0; x < (ssize_t) image->columns; x++)
946 {
947 double
948 gamma,
949 opacity;
950
951 gamma=1.0-QuantumScale*QuantumScale*(double) q->opacity*(double)
952 pixel.opacity;
953 opacity=(double) QuantumRange*(1.0-gamma);
954 gamma=PerceptibleReciprocal(gamma);
955 q->red=ClampToQuantum(gamma*MagickOver_((MagickRealType) q->red,
956 (MagickRealType) q->opacity,(MagickRealType) pixel.red,
957 (MagickRealType) pixel.opacity));
958 q->green=ClampToQuantum(gamma*MagickOver_((MagickRealType) q->green,
959 (MagickRealType) q->opacity,(MagickRealType) pixel.green,
960 (MagickRealType) pixel.opacity));
961 q->blue=ClampToQuantum(gamma*MagickOver_((MagickRealType) q->blue,
962 (MagickRealType) q->opacity,(MagickRealType) pixel.blue,
963 (MagickRealType) pixel.opacity));
964 q->opacity=ClampToQuantum(opacity);
965 q++;
966 }
967 if (image->colorspace == CMYKColorspace)
968 {
969 indexes=GetCacheViewAuthenticIndexQueue(image_view);
970 for (x=0; x < (ssize_t) image->columns; x++)
971 SetPixelIndex(indexes+x,index);
972 }
973 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
974 status=MagickFalse;
975 }
976 image_view=DestroyCacheView(image_view);
977 return(status);
978 }
979 case ResetAlphaChannel: /* deprecated */
980 case OpaqueAlphaChannel:
981 {
982 status=SetImageOpacity(image,OpaqueOpacity);
983 break;
984 }
985 case SetAlphaChannel:
986 {
987 if (image->matte == MagickFalse)
988 status=SetImageOpacity(image,OpaqueOpacity);
989 break;
990 }
991 case TransparentAlphaChannel:
992 {
993 status=SetImageOpacity(image,TransparentOpacity);
994 break;
995 }
996 case UndefinedAlphaChannel:
997 break;
998 }
999 if (status == MagickFalse)
1000 return(status);
1001 return(SyncImagePixelCache(image,&image->exception));
1002}