MagickCore 6.9.13-47
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/license/ %
27% %
28% Unless required by applicable law or agreed to in writing, software %
29% distributed under the License is distributed on an "AS IS" BASIS, %
30% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31% See the License for the specific language governing permissions and %
32% limitations under the License. %
33% %
34%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35%
36%
37%
38*/
39
40/*
41 Include declarations.
42*/
43#include "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
98 CacheView
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 {
161 CacheView
162 *image_view;
163
164 const Image
165 *next;
166
167 PixelPacket
168 *pixels;
169
170 const PixelPacket
171 *magick_restrict p;
172
173 PixelPacket
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 else
295 combine_image->type=UndefinedType;
296 return(combine_image);
297}
298
299/*
300%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
301% %
302% %
303% %
304% G e t I m a g e A l p h a C h a n n e l %
305% %
306% %
307% %
308%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
309%
310% GetImageAlphaChannel() returns MagickFalse if the image alpha channel is
311% not activated. That is, the image is RGB rather than RGBA or CMYK rather
312% than CMYKA.
313%
314% The format of the GetImageAlphaChannel method is:
315%
316% MagickBooleanType GetImageAlphaChannel(const Image *image)
317%
318% A description of each parameter follows:
319%
320% o image: the image.
321%
322*/
323MagickExport MagickBooleanType GetImageAlphaChannel(const Image *image)
324{
325 assert(image != (const Image *) NULL);
326 if (IsEventLogging() != MagickFalse)
327 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
328 assert(image->signature == MagickCoreSignature);
329 return(image->matte);
330}
331
332/*
333%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
334% %
335% %
336% %
337% S e p a r a t e I m a g e C h a n n e l %
338% %
339% %
340% %
341%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
342%
343% SeparateImageChannel() separates a channel from the image and returns it as
344% a grayscale image. A channel is a particular color component of each pixel
345% in the image.
346%
347% The format of the SeparateImageChannel method is:
348%
349% MagickBooleanType SeparateImageChannel(Image *image,
350% const ChannelType channel)
351%
352% A description of each parameter follows:
353%
354% o image: the image.
355%
356% o channel: Identify which channel to extract: RedChannel, GreenChannel,
357% BlueChannel, OpacityChannel, CyanChannel, MagentaChannel,
358% YellowChannel, or BlackChannel.
359%
360*/
361
362MagickExport Image *SeparateImage(const Image *image,const ChannelType channel,
363 ExceptionInfo *exception)
364{
365 Image
366 *separate_image;
367
368 MagickBooleanType
369 status;
370
371 /*
372 Initialize separate image attributes.
373 */
374 assert(image != (Image *) NULL);
375 assert(image->signature == MagickCoreSignature);
376 if (IsEventLogging() != MagickFalse)
377 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
378 assert(exception != (ExceptionInfo *) NULL);
379 assert(exception->signature == MagickCoreSignature);
380 separate_image=CloneImage(image,0,0,MagickTrue,exception);
381 if (separate_image == (Image *) NULL)
382 return((Image *) NULL);
383 status=SeparateImageChannel(separate_image,channel);
384 if (status == MagickFalse)
385 separate_image=DestroyImage(separate_image);
386 return(separate_image);
387}
388
389MagickExport MagickBooleanType SeparateImageChannel(Image *image,
390 const ChannelType channel)
391{
392#define SeparateImageTag "Separate/Image"
393
394 CacheView
395 *image_view;
396
397 ExceptionInfo
398 *exception;
399
400 MagickBooleanType
401 status;
402
403 MagickOffsetType
404 progress;
405
406 ssize_t
407 y;
408
409 assert(image != (Image *) NULL);
410 assert(image->signature == MagickCoreSignature);
411 if (IsEventLogging() != MagickFalse)
412 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
413 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
414 return(MagickFalse);
415 if (channel == GrayChannels)
416 (void) SetImageAlphaChannel(image,OpaqueAlphaChannel);
417 /*
418 Separate image channels.
419 */
420 status=MagickTrue;
421 progress=0;
422 exception=(&image->exception);
423 image_view=AcquireAuthenticCacheView(image,exception);
424#if defined(MAGICKCORE_OPENMP_SUPPORT)
425 #pragma omp parallel for schedule(static) shared(progress,status) \
426 magick_number_threads(image,image,image->rows,2)
427#endif
428 for (y=0; y < (ssize_t) image->rows; y++)
429 {
430 IndexPacket
431 *magick_restrict indexes;
432
433 PixelPacket
434 *magick_restrict q;
435
436 ssize_t
437 x;
438
439 if (status == MagickFalse)
440 continue;
441 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
442 if (q == (PixelPacket *) NULL)
443 {
444 status=MagickFalse;
445 continue;
446 }
447 indexes=GetCacheViewAuthenticIndexQueue(image_view);
448 switch (channel)
449 {
450 case RedChannel:
451 {
452 for (x=0; x < (ssize_t) image->columns; x++)
453 {
454 SetPixelGreen(q,GetPixelRed(q));
455 SetPixelBlue(q,GetPixelRed(q));
456 q++;
457 }
458 break;
459 }
460 case GreenChannel:
461 {
462 for (x=0; x < (ssize_t) image->columns; x++)
463 {
464 SetPixelRed(q,GetPixelGreen(q));
465 SetPixelBlue(q,GetPixelGreen(q));
466 q++;
467 }
468 break;
469 }
470 case BlueChannel:
471 {
472 for (x=0; x < (ssize_t) image->columns; x++)
473 {
474 SetPixelRed(q,GetPixelBlue(q));
475 SetPixelGreen(q,GetPixelBlue(q));
476 q++;
477 }
478 break;
479 }
480 case OpacityChannel:
481 {
482 for (x=0; x < (ssize_t) image->columns; x++)
483 {
484 SetPixelRed(q,GetPixelOpacity(q));
485 SetPixelGreen(q,GetPixelOpacity(q));
486 SetPixelBlue(q,GetPixelOpacity(q));
487 q++;
488 }
489 break;
490 }
491 case BlackChannel:
492 {
493 if ((image->storage_class != PseudoClass) &&
494 (image->colorspace != CMYKColorspace))
495 break;
496 for (x=0; x < (ssize_t) image->columns; x++)
497 {
498 SetPixelRed(q,GetPixelIndex(indexes+x));
499 SetPixelGreen(q,GetPixelIndex(indexes+x));
500 SetPixelBlue(q,GetPixelIndex(indexes+x));
501 q++;
502 }
503 break;
504 }
505 case TrueAlphaChannel:
506 {
507 for (x=0; x < (ssize_t) image->columns; x++)
508 {
509 SetPixelRed(q,GetPixelAlpha(q));
510 SetPixelGreen(q,GetPixelAlpha(q));
511 SetPixelBlue(q,GetPixelAlpha(q));
512 q++;
513 }
514 break;
515 }
516 case GrayChannels:
517 {
518 for (x=0; x < (ssize_t) image->columns; x++)
519 {
520 SetPixelAlpha(q,ClampToQuantum(GetPixelIntensity(image,q)));
521 q++;
522 }
523 break;
524 }
525 default:
526 break;
527 }
528 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
529 status=MagickFalse;
530 if (image->progress_monitor != (MagickProgressMonitor) NULL)
531 {
532 MagickBooleanType
533 proceed;
534
535#if defined(MAGICKCORE_OPENMP_SUPPORT)
536 #pragma omp atomic
537#endif
538 progress++;
539 proceed=SetImageProgress(image,SeparateImageTag,progress,image->rows);
540 if (proceed == MagickFalse)
541 status=MagickFalse;
542 }
543 }
544 image_view=DestroyCacheView(image_view);
545 if (channel != GrayChannels)
546 {
547 image->matte=MagickFalse;
548 (void) SetImageColorspace(image,GRAYColorspace);
549 }
550 return(status);
551}
552
553/*
554%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
555% %
556% %
557% %
558% S e p a r a t e I m a g e s %
559% %
560% %
561% %
562%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
563%
564% SeparateImages() returns a separate grayscale image for each channel
565% specified.
566%
567% The format of the SeparateImages method is:
568%
569% MagickBooleanType SeparateImages(const Image *image,
570% const ChannelType channel,ExceptionInfo *exception)
571%
572% A description of each parameter follows:
573%
574% o image: the image.
575%
576% o channel: Identify which channels to extract: RedChannel, GreenChannel,
577% BlueChannel, OpacityChannel, CyanChannel, MagentaChannel,
578% YellowChannel, or BlackChannel.
579%
580% o exception: return any errors or warnings in this structure.
581%
582*/
583MagickExport Image *SeparateImages(const Image *image,const ChannelType channel,
584 ExceptionInfo *exception)
585{
586 Image
587 *images,
588 *separate_image;
589
590 assert(image != (Image *) NULL);
591 assert(image->signature == MagickCoreSignature);
592 if (IsEventLogging() != MagickFalse)
593 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
594 images=NewImageList();
595 if ((channel & RedChannel) != 0)
596 {
597 separate_image=CloneImage(image,0,0,MagickTrue,exception);
598 (void) SeparateImageChannel(separate_image,RedChannel);
599 AppendImageToList(&images,separate_image);
600 }
601 if ((channel & GreenChannel) != 0)
602 {
603 separate_image=CloneImage(image,0,0,MagickTrue,exception);
604 (void) SeparateImageChannel(separate_image,GreenChannel);
605 AppendImageToList(&images,separate_image);
606 }
607 if ((channel & BlueChannel) != 0)
608 {
609 separate_image=CloneImage(image,0,0,MagickTrue,exception);
610 (void) SeparateImageChannel(separate_image,BlueChannel);
611 AppendImageToList(&images,separate_image);
612 }
613 if (((channel & BlackChannel) != 0) && (image->colorspace == CMYKColorspace))
614 {
615 separate_image=CloneImage(image,0,0,MagickTrue,exception);
616 (void) SeparateImageChannel(separate_image,BlackChannel);
617 AppendImageToList(&images,separate_image);
618 }
619 if ((channel & AlphaChannel) != 0)
620 {
621 separate_image=CloneImage(image,0,0,MagickTrue,exception);
622 (void) SeparateImageChannel(separate_image,TrueAlphaChannel);
623 AppendImageToList(&images,separate_image);
624 }
625 return(images);
626}
627
628/*
629%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
630% %
631% %
632% %
633% S e t I m a g e A l p h a C h a n n e l %
634% %
635% %
636% %
637%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
638%
639% SetImageAlphaChannel() activates, deactivates, resets, or sets the alpha
640% channel.
641%
642% The format of the SetImageAlphaChannel method is:
643%
644% MagickBooleanType SetImageAlphaChannel(Image *image,
645% const AlphaChannelType alpha_type)
646%
647% A description of each parameter follows:
648%
649% o image: the image.
650%
651% o alpha_type: The alpha channel type: ActivateAlphaChannel,
652% AssociateAlphaChannel, CopyAlphaChannel, Disassociate,
653% DeactivateAlphaChannel, ExtractAlphaChannel, OpaqueAlphaChannel,
654% ResetAlphaChannel, SetAlphaChannel, ShapeAlphaChannel, and
655% TransparentAlphaChannel.
656%
657*/
658MagickExport MagickBooleanType SetImageAlphaChannel(Image *image,
659 const AlphaChannelType alpha_type)
660{
661 CacheView
662 *image_view;
663
664 ExceptionInfo
665 *exception;
666
667 MagickBooleanType
668 status;
669
670 ssize_t
671 y;
672
673 assert(image != (Image *) NULL);
674 if (IsEventLogging() != MagickFalse)
675 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
676 assert(image->signature == MagickCoreSignature);
677 exception=(&image->exception);
678 status=MagickTrue;
679 switch (alpha_type)
680 {
681 case ActivateAlphaChannel:
682 {
683 if (image->matte == MagickTrue)
684 return(status);
685 image->matte=MagickTrue;
686 break;
687 }
688 case AssociateAlphaChannel:
689 {
690 /*
691 Associate alpha.
692 */
693 status=SetImageStorageClass(image,DirectClass);
694 if (status == MagickFalse)
695 break;
696 image_view=AcquireAuthenticCacheView(image,exception);
697 #if defined(MAGICKCORE_OPENMP_SUPPORT)
698 #pragma omp parallel for schedule(static) shared(status) \
699 magick_number_threads(image,image,image->rows,2)
700 #endif
701 for (y=0; y < (ssize_t) image->rows; y++)
702 {
703 PixelPacket
704 *magick_restrict q;
705
706 ssize_t
707 x;
708
709 if (status == MagickFalse)
710 continue;
711 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
712 exception);
713 if (q == (PixelPacket *) NULL)
714 {
715 status=MagickFalse;
716 continue;
717 }
718 for (x=0; x < (ssize_t) image->columns; x++)
719 {
720 double
721 gamma;
722
723 gamma=QuantumScale*(double) GetPixelAlpha(q);
724 SetPixelRed(q,ClampToQuantum(gamma*(double) GetPixelRed(q)));
725 SetPixelGreen(q,ClampToQuantum(gamma*(double) GetPixelGreen(q)));
726 SetPixelBlue(q,ClampToQuantum(gamma*(double) GetPixelBlue(q)));
727 q++;
728 }
729 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
730 status=MagickFalse;
731 }
732 image_view=DestroyCacheView(image_view);
733 image->matte=MagickFalse;
734 break;
735 }
736 case BackgroundAlphaChannel:
737 {
738 IndexPacket
739 index;
740
741 MagickBooleanType
742 status;
743
744 MagickPixelPacket
745 background;
746
747 PixelPacket
748 pixel;
749
750 /*
751 Set transparent pixels to background color.
752 */
753 if (image->matte == MagickFalse)
754 break;
755 status=SetImageStorageClass(image,DirectClass);
756 if (status == MagickFalse)
757 break;
758 GetMagickPixelPacket(image,&background);
759 SetMagickPixelPacket(image,&image->background_color,(const IndexPacket *)
760 NULL,&background);
761 if (image->colorspace == CMYKColorspace)
762 ConvertRGBToCMYK(&background);
763 index=0;
764 SetPixelPacket(image,&background,&pixel,&index);
765 status=MagickTrue;
766 exception=(&image->exception);
767 image_view=AcquireAuthenticCacheView(image,exception);
768 #if defined(MAGICKCORE_OPENMP_SUPPORT)
769 #pragma omp parallel for schedule(static) shared(status) \
770 magick_number_threads(image,image,image->rows,2)
771 #endif
772 for (y=0; y < (ssize_t) image->rows; y++)
773 {
774 IndexPacket
775 *magick_restrict indexes;
776
777 PixelPacket
778 *magick_restrict q;
779
780 ssize_t
781 x;
782
783 if (status == MagickFalse)
784 continue;
785 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
786 exception);
787 if (q == (PixelPacket *) NULL)
788 {
789 status=MagickFalse;
790 continue;
791 }
792 for (x=0; x < (ssize_t) image->columns; x++)
793 {
794 if (q->opacity == TransparentOpacity)
795 {
796 SetPixelRed(q,pixel.red);
797 SetPixelGreen(q,pixel.green);
798 SetPixelBlue(q,pixel.blue);
799 }
800 q++;
801 }
802 if (image->colorspace == CMYKColorspace)
803 {
804 indexes=GetCacheViewAuthenticIndexQueue(image_view);
805 for (x=0; x < (ssize_t) image->columns; x++)
806 SetPixelIndex(indexes+x,index);
807 }
808 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
809 status=MagickFalse;
810 }
811 image_view=DestroyCacheView(image_view);
812 return(status);
813 }
814 case CopyAlphaChannel:
815 case ShapeAlphaChannel:
816 {
817 /*
818 Special usage case for SeparateImageChannel(): copy grayscale color to
819 the alpha channel.
820 */
821 status=SeparateImageChannel(image,GrayChannels);
822 image->matte=MagickTrue; /* make sure transparency is now on! */
823 if (alpha_type == ShapeAlphaChannel)
824 {
825 MagickPixelPacket
826 background;
827
828 /*
829 Reset all color channels to background color.
830 */
831 GetMagickPixelPacket(image,&background);
832 SetMagickPixelPacket(image,&(image->background_color),(IndexPacket *)
833 NULL,&background);
834 (void) LevelColorsImage(image,&background,&background,MagickTrue);
835 }
836 break;
837 }
838 case DeactivateAlphaChannel:
839 {
840 if (image->matte == MagickFalse)
841 return(status);
842 image->matte=MagickFalse;
843 break;
844 }
845 case DisassociateAlphaChannel:
846 {
847 status=SetImageStorageClass(image,DirectClass);
848 if (status == MagickFalse)
849 break;
850 image->matte=MagickTrue;
851 image_view=AcquireAuthenticCacheView(image,exception);
852 #if defined(MAGICKCORE_OPENMP_SUPPORT)
853 #pragma omp parallel for schedule(static) shared(status) \
854 magick_number_threads(image,image,image->rows,2)
855 #endif
856 for (y=0; y < (ssize_t) image->rows; y++)
857 {
858 PixelPacket
859 *magick_restrict q;
860
861 ssize_t
862 x;
863
864 if (status == MagickFalse)
865 continue;
866 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
867 exception);
868 if (q == (PixelPacket *) NULL)
869 {
870 status=MagickFalse;
871 continue;
872 }
873 for (x=0; x < (ssize_t) image->columns; x++)
874 {
875 double
876 alpha,
877 gamma;
878
879 alpha=QuantumScale*(double) GetPixelAlpha(q);
880 gamma=MagickSafeReciprocal(alpha);
881 SetPixelRed(q,ClampToQuantum(gamma*(double) GetPixelRed(q)));
882 SetPixelGreen(q,ClampToQuantum(gamma*(double) GetPixelGreen(q)));
883 SetPixelBlue(q,ClampToQuantum(gamma*(double) GetPixelBlue(q)));
884 q++;
885 }
886 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
887 status=MagickFalse;
888 }
889 image_view=DestroyCacheView(image_view);
890 image->matte=MagickFalse;
891 break;
892 }
893 case ExtractAlphaChannel:
894 {
895 status=SeparateImageChannel(image,TrueAlphaChannel);
896 image->matte=MagickFalse;
897 break;
898 }
899 case OffIfOpaqueAlphaChannel:
900 {
901 MagickBooleanType
902 opaque = MagickTrue;
903
904 /*
905 Remove opaque alpha channel.
906 */
907 image_view=AcquireVirtualCacheView(image,exception);
908 #if defined(MAGICKCORE_OPENMP_SUPPORT)
909 #pragma omp parallel for schedule(static) shared(opaque,status) \
910 magick_number_threads(image,image,image->rows,2)
911 #endif
912 for (y=0; y < (ssize_t) image->rows; y++)
913 {
914 const PixelPacket
915 *magick_restrict p;
916
917 ssize_t
918 x;
919
920 if ((status == MagickFalse) || (opaque == MagickFalse))
921 continue;
922 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
923 if (p == (const PixelPacket *) NULL)
924 {
925 status=MagickFalse;
926 continue;
927 }
928 for (x=0; x < (ssize_t) image->columns; x++)
929 {
930 if (GetPixelOpacity(p) != OpaqueOpacity)
931 {
932 opaque=MagickFalse;
933 break;
934 }
935 p++;
936 }
937 }
938 image_view=DestroyCacheView(image_view);
939 if (opaque != MagickFalse)
940 image->matte=MagickFalse;
941 break;
942 }
943 case ResetAlphaChannel: /* deprecated */
944 case RemoveAlphaChannel:
945 case FlattenAlphaChannel:
946 {
947 IndexPacket
948 index;
949
950 MagickPixelPacket
951 background;
952
953 PixelPacket
954 pixel;
955
956 /*
957 Flatten image pixels over the background pixels.
958 */
959 if (image->matte == MagickFalse)
960 break;
961 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
962 break;
963 GetMagickPixelPacket(image,&background);
964 SetMagickPixelPacket(image,&image->background_color,(const IndexPacket *)
965 NULL,&background);
966 if (image->colorspace == CMYKColorspace)
967 ConvertRGBToCMYK(&background);
968 (void) memset(&pixel,0,sizeof(pixel));
969 index=0;
970 SetPixelPacket(image,&background,&pixel,&index);
971 image_view=AcquireAuthenticCacheView(image,exception);
972 #if defined(MAGICKCORE_OPENMP_SUPPORT)
973 #pragma omp parallel for schedule(static) shared(status) \
974 magick_number_threads(image,image,image->rows,2)
975 #endif
976 for (y=0; y < (ssize_t) image->rows; y++)
977 {
978 IndexPacket
979 *magick_restrict indexes;
980
981 PixelPacket
982 *magick_restrict q;
983
984 ssize_t
985 x;
986
987 if (status == MagickFalse)
988 continue;
989 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
990 exception);
991 if (q == (PixelPacket *) NULL)
992 {
993 status=MagickFalse;
994 continue;
995 }
996 for (x=0; x < (ssize_t) image->columns; x++)
997 {
998 double
999 gamma,
1000 opacity;
1001
1002 gamma=1.0-QuantumScale*QuantumScale*(double) q->opacity*(double)
1003 pixel.opacity;
1004 opacity=(double) QuantumRange*(1.0-gamma);
1005 gamma=MagickSafeReciprocal(gamma);
1006 q->red=ClampToQuantum(gamma*MagickOver_((MagickRealType) q->red,
1007 (MagickRealType) q->opacity,(MagickRealType) pixel.red,
1008 (MagickRealType) pixel.opacity));
1009 q->green=ClampToQuantum(gamma*MagickOver_((MagickRealType) q->green,
1010 (MagickRealType) q->opacity,(MagickRealType) pixel.green,
1011 (MagickRealType) pixel.opacity));
1012 q->blue=ClampToQuantum(gamma*MagickOver_((MagickRealType) q->blue,
1013 (MagickRealType) q->opacity,(MagickRealType) pixel.blue,
1014 (MagickRealType) pixel.opacity));
1015 q->opacity=ClampToQuantum(opacity);
1016 q++;
1017 }
1018 if (image->colorspace == CMYKColorspace)
1019 {
1020 indexes=GetCacheViewAuthenticIndexQueue(image_view);
1021 for (x=0; x < (ssize_t) image->columns; x++)
1022 SetPixelIndex(indexes+x,index);
1023 }
1024 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
1025 status=MagickFalse;
1026 }
1027 image_view=DestroyCacheView(image_view);
1028 return(status);
1029 }
1030 case OpaqueAlphaChannel:
1031 {
1032 status=SetImageOpacity(image,OpaqueOpacity);
1033 break;
1034 }
1035 case SetAlphaChannel:
1036 {
1037 if (image->matte == MagickFalse)
1038 status=SetImageOpacity(image,OpaqueOpacity);
1039 break;
1040 }
1041 case TransparentAlphaChannel:
1042 {
1043 status=SetImageOpacity(image,TransparentOpacity);
1044 break;
1045 }
1046 case UndefinedAlphaChannel:
1047 break;
1048 }
1049 if (status == MagickFalse)
1050 return(status);
1051 return(SyncImagePixelCache(image,&image->exception));
1052}