MagickCore  6.9.12-67
Convert, Edit, Or Compose Bitmap Images
 All Data Structures
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-2021 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 */
93 MagickExport 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  for (y=0; y < (ssize_t) combine_image->rows; y++)
156  {
157  CacheView
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 */
317 MagickExport 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 
356 MagickExport 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 
383 MagickExport MagickBooleanType SeparateImageChannel(Image *image,
384  const ChannelType channel)
385 {
386 #define SeparateImageTag "Separate/Image"
387 
388  CacheView
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 */
577 MagickExport 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 */
652 MagickExport MagickBooleanType SetImageAlphaChannel(Image *image,
653  const AlphaChannelType alpha_type)
654 {
655  CacheView
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*GetPixelAlpha(q);
718  SetPixelRed(q,ClampToQuantum(gamma*GetPixelRed(q)));
719  SetPixelGreen(q,ClampToQuantum(gamma*GetPixelGreen(q)));
720  SetPixelBlue(q,ClampToQuantum(gamma*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*GetPixelAlpha(q);
874  gamma=PerceptibleReciprocal(alpha);
875  SetPixelRed(q,ClampToQuantum(gamma*GetPixelRed(q)));
876  SetPixelGreen(q,ClampToQuantum(gamma*GetPixelGreen(q)));
877  SetPixelBlue(q,ClampToQuantum(gamma*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*q->opacity*pixel.opacity;
952  opacity=(double) QuantumRange*(1.0-gamma);
953  gamma=PerceptibleReciprocal(gamma);
954  q->red=ClampToQuantum(gamma*MagickOver_((MagickRealType) q->red,
955  (MagickRealType) q->opacity,(MagickRealType) pixel.red,
956  (MagickRealType) pixel.opacity));
957  q->green=ClampToQuantum(gamma*MagickOver_((MagickRealType) q->green,
958  (MagickRealType) q->opacity,(MagickRealType) pixel.green,
959  (MagickRealType) pixel.opacity));
960  q->blue=ClampToQuantum(gamma*MagickOver_((MagickRealType) q->blue,
961  (MagickRealType) q->opacity,(MagickRealType) pixel.blue,
962  (MagickRealType) pixel.opacity));
963  q->opacity=ClampToQuantum(opacity);
964  q++;
965  }
966  if (image->colorspace == CMYKColorspace)
967  {
968  indexes=GetCacheViewAuthenticIndexQueue(image_view);
969  for (x=0; x < (ssize_t) image->columns; x++)
970  SetPixelIndex(indexes+x,index);
971  }
972  if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
973  status=MagickFalse;
974  }
975  image_view=DestroyCacheView(image_view);
976  return(status);
977  }
978  case ResetAlphaChannel: /* deprecated */
979  case OpaqueAlphaChannel:
980  {
981  status=SetImageOpacity(image,OpaqueOpacity);
982  break;
983  }
984  case SetAlphaChannel:
985  {
986  if (image->matte == MagickFalse)
987  status=SetImageOpacity(image,OpaqueOpacity);
988  break;
989  }
990  case TransparentAlphaChannel:
991  {
992  status=SetImageOpacity(image,TransparentOpacity);
993  break;
994  }
995  case UndefinedAlphaChannel:
996  break;
997  }
998  if (status == MagickFalse)
999  return(status);
1000  return(SyncImagePixelCache(image,&image->exception));
1001 }
Definition: image.h:152