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