MagickCore  6.9.13-47
Convert, Edit, Or Compose Bitmap Images
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 */
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 #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 
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  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 */
323 MagickExport 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 
362 MagickExport 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 
389 MagickExport MagickBooleanType SeparateImageChannel(Image *image,
390  const ChannelType channel)
391 {
392 #define SeparateImageTag "Separate/Image"
393 
394  CacheView
395  *image_view;
396 
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 
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 */
583 MagickExport 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 */
658 MagickExport MagickBooleanType SetImageAlphaChannel(Image *image,
659  const AlphaChannelType alpha_type)
660 {
661  CacheView
662  *image_view;
663 
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  {
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 
745  background;
746 
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 
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  {
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  {
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 
951  background;
952 
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 
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 }
Definition: image.h:134