2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
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 RRR 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 %
13 % MagickCore Image Channel Methods %
20 % Copyright 1999-2012 ImageMagick Studio LLC, a non-profit organization %
21 % dedicated to making software imaging solutions freely available. %
23 % You may not use this file except in compliance with the License. You may %
24 % obtain a copy of the License at %
26 % http://www.imagemagick.org/script/license.php %
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. %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
43 #include "MagickCore/studio.h"
44 #include "MagickCore/image.h"
45 #include "MagickCore/list.h"
46 #include "MagickCore/log.h"
47 #include "MagickCore/monitor.h"
48 #include "MagickCore/monitor-private.h"
49 #include "MagickCore/option.h"
50 #include "MagickCore/pixel-accessor.h"
51 #include "MagickCore/token.h"
52 #include "MagickCore/utility.h"
53 #include "MagickCore/version.h"
56 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
60 % C h a n n e l F x I m a g e %
64 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
66 % ChannelFxImage() applies a channel expression to the specified image. The
67 % expression consists of one or more channels, either mnemonic or numeric (e.g.
68 % red, 1), separated by actions as follows:
70 % <=> exchange two channels (e.g. red<=>blue)
71 % => transfer a channel to another (e.g. red=>green)
72 % , separate channel operations (e.g. red, green)
73 % | read channels from next input image (e.g. red | green)
74 % ; write channels to next output image (e.g. red; green; blue)
76 % A channel without a operation symbol implies extract. For example, to create
77 % 3 grayscale images from the red, green, and blue channels of an image, use:
79 % -channel-fx "red; green; blue"
81 % The format of the ChannelFxImage method is:
83 % Image *ChannelFxImage(const Image *image,const char *expression,
84 % ExceptionInfo *exception)
86 % A description of each parameter follows:
90 % o expression: A channel expression.
92 % o exception: return any errors or warnings in this structure.
103 static inline size_t MagickMin(const size_t x,const size_t y)
110 static MagickBooleanType ChannelImage(Image *destination_image,
111 const Image *source_image,const ChannelFx channel_op,
112 const PixelChannel source_channel,const PixelChannel destination_channel,
113 ExceptionInfo *exception)
129 source_view=AcquireCacheView(source_image);
130 destination_view=AcquireCacheView(destination_image);
131 height=MagickMin(source_image->rows,destination_image->rows);
132 #if defined(MAGICKCORE_OPENMP_SUPPORT)
133 #pragma omp parallel for schedule(static) shared(status)
135 for (y=0; y < (ssize_t) height; y++)
137 register const Quantum
149 if (status == MagickFalse)
151 p=GetCacheViewVirtualPixels(source_view,0,y,source_image->columns,1,
153 q=QueueCacheViewAuthenticPixels(destination_view,0,y,
154 destination_image->columns,1,exception);
155 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
160 width=MagickMin(source_image->columns,destination_image->columns);
161 for (x=0; x < (ssize_t) width; x++)
170 source_traits=GetPixelChannelMapTraits(source_image,source_channel);
171 destination_traits=GetPixelChannelMapTraits(destination_image,
172 destination_channel);
173 if ((source_traits == UndefinedPixelTrait) ||
174 (destination_traits == UndefinedPixelTrait))
176 offset=GetPixelChannelMapOffset(source_image,source_channel);
177 SetPixelChannel(destination_image,destination_channel,p[offset],q);
178 p+=GetPixelChannels(source_image);
179 q+=GetPixelChannels(destination_image);
181 if (SyncCacheViewAuthenticPixels(destination_view,exception) == MagickFalse)
184 destination_view=DestroyCacheView(destination_view);
185 source_view=DestroyCacheView(source_view);
189 MagickExport Image *ChannelFxImage(const Image *image,const char *expression,
190 ExceptionInfo *exception)
192 #define ChannelFxImageTag "ChannelFx/Image"
195 token[MaxTextExtent];
216 assert(image != (Image *) NULL);
217 assert(image->signature == MagickSignature);
218 if (image->debug != MagickFalse)
219 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
220 assert(exception != (ExceptionInfo *) NULL);
221 assert(exception->signature == MagickSignature);
223 destination_image=CloneImage(source_image,0,0,MagickTrue,exception);
224 if (destination_image == (Image *) NULL)
225 return((Image *) NULL);
226 if (SetImageBackgroundColor(destination_image,exception) == MagickFalse)
228 destination_image=GetLastImageInList(destination_image);
229 return((Image *) NULL);
231 if (expression == (const char *) NULL)
232 return(destination_image);
233 destination_channel=RedPixelChannel;
234 p=(char *) expression;
235 GetMagickToken(p,&p,token);
236 for (channels=0; *p != '\0'; )
245 Interpret channel expression.
249 destination_channel=(PixelChannel) ((ssize_t) destination_channel+1);
250 GetMagickToken(p,&p,token);
254 if (GetNextImageInList(source_image) != (Image *) NULL)
255 source_image=GetNextImageInList(source_image);
257 source_image=GetFirstImageInList(source_image);
258 GetMagickToken(p,&p,token);
267 destination_image->colorspace=GRAYColorspace;
268 InitializePixelChannelMap(destination_image);
270 canvas=CloneImage(source_image,0,0,MagickTrue,exception);
271 if (canvas == (Image *) NULL)
273 destination_image=GetLastImageInList(destination_image);
274 return((Image *) NULL);
276 AppendImageToList(&destination_image,canvas);
277 destination_image=GetLastImageInList(destination_image);
278 if (SetImageBackgroundColor(destination_image,exception) == MagickFalse)
280 destination_image=GetLastImageInList(destination_image);
281 return((Image *) NULL);
283 GetMagickToken(p,&p,token);
285 destination_channel=RedPixelChannel;
287 i=ParsePixelChannelOption(token);
290 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
291 "UnrecognizedChannelType","`%s'",token);
292 destination_image=DestroyImageList(destination_image);
295 source_channel=(PixelChannel) i;
296 channel_op=ExtractChannelOp;
297 GetMagickToken(p,&p,token);
300 channel_op=ExchangeChannelOp;
301 GetMagickToken(p,&p,token);
304 GetMagickToken(p,&p,token);
307 if (channel_op != ExchangeChannelOp)
308 channel_op=TransferChannelOp;
309 GetMagickToken(p,&p,token);
311 if (channel_op != ExtractChannelOp)
313 i=ParsePixelChannelOption(token);
316 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
317 "UnrecognizedChannelType","`%s'",token);
318 destination_image=DestroyImageList(destination_image);
321 destination_channel=(PixelChannel) i;
323 status=ChannelImage(destination_image,source_image,channel_op,
324 source_channel,destination_channel,exception);
325 if (status == MagickFalse)
327 destination_image=DestroyImageList(destination_image);
331 status=SetImageProgress(source_image,ChannelFxImageTag,p-expression,
333 if (status == MagickFalse)
338 destination_image->colorspace=GRAYColorspace;
339 InitializePixelChannelMap(destination_image);
341 return(destination_image);
345 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
349 % C o m b i n e I m a g e s %
353 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
355 % CombineImages() combines one or more images into a single image. The
356 % grayscale value of the pixels of each image in the sequence is assigned in
357 % order to the specified channels of the combined image. The typical
358 % ordering would be image 1 => Red, 2 => Green, 3 => Blue, etc.
360 % The format of the CombineImages method is:
362 % Image *CombineImages(const Image *image,ExceptionInfo *exception)
364 % A description of each parameter follows:
366 % o image: the image.
368 % o exception: return any errors or warnings in this structure.
371 MagickExport Image *CombineImages(const Image *image,ExceptionInfo *exception)
373 #define CombineImageTag "Combine/Image"
391 Ensure the image are the same size.
393 assert(image != (const Image *) NULL);
394 assert(image->signature == MagickSignature);
395 if (image->debug != MagickFalse)
396 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
397 assert(exception != (ExceptionInfo *) NULL);
398 assert(exception->signature == MagickSignature);
399 combine_image=CloneImage(image,0,0,MagickTrue,exception);
400 if (combine_image == (Image *) NULL)
401 return((Image *) NULL);
402 if (SetImageStorageClass(combine_image,DirectClass,exception) == MagickFalse)
404 combine_image=DestroyImage(combine_image);
405 return((Image *) NULL);
407 if ((GetPixelAlphaTraits(image) & UpdatePixelTrait) != 0)
408 combine_image->matte=MagickTrue;
414 combine_view=AcquireCacheView(combine_image);
415 for (y=0; y < (ssize_t) combine_image->rows; y++)
426 register const Quantum
435 if (status == MagickFalse)
437 pixels=GetCacheViewAuthenticPixels(combine_view,0,y,combine_image->columns,
439 if (pixels == (Quantum *) NULL)
445 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
457 if (next == (Image *) NULL)
459 channel=GetPixelChannelMapChannel(image,i);
460 traits=GetPixelChannelMapTraits(image,channel);
461 combine_traits=GetPixelChannelMapTraits(combine_image,channel);
462 if ((traits == UndefinedPixelTrait) ||
463 (combine_traits == UndefinedPixelTrait))
465 image_view=AcquireCacheView(next);
466 p=GetCacheViewVirtualPixels(image_view,0,y,next->columns,1,exception);
467 if (p == (const Quantum *) NULL)
470 for (x=0; x < (ssize_t) combine_image->columns; x++)
472 if (x < (ssize_t) image->columns)
474 q[i]=GetPixelGray(image,p);
475 p+=GetPixelChannels(image);
477 q+=GetPixelChannels(combine_image);
479 image_view=DestroyCacheView(image_view);
480 next=GetNextImageInList(next);
481 if (SyncCacheViewAuthenticPixels(combine_view,exception) == MagickFalse)
483 if (image->progress_monitor != (MagickProgressMonitor) NULL)
488 proceed=SetImageProgress(image,CombineImageTag,progress++,
489 combine_image->rows);
490 if (proceed == MagickFalse)
495 combine_view=DestroyCacheView(combine_view);
496 if (status == MagickFalse)
497 combine_image=DestroyImage(combine_image);
498 return(combine_image);
502 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
506 % S e p a r a t e I m a g e %
510 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
512 % SeparateImage() separates a channel from the image and returns it as a
515 % The format of the SeparateImage method is:
517 % Image *SeparateImage(const Image *image,const ChannelType channel,
518 % ExceptionInfo *exception)
520 % A description of each parameter follows:
522 % o image: the image.
524 % o channel: the image channel.
526 % o exception: return any errors or warnings in this structure.
529 MagickExport Image *SeparateImage(const Image *image,
530 const ChannelType channel_type,ExceptionInfo *exception)
532 #define GetChannelBit(mask,bit) (((size_t) (mask) >> (size_t) (bit)) & 0x01)
533 #define SeparateImageTag "Separate/Image"
552 Initialize spread image attributes.
554 assert(image != (Image *) NULL);
555 assert(image->signature == MagickSignature);
556 if (image->debug != MagickFalse)
557 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
558 assert(exception != (ExceptionInfo *) NULL);
559 assert(exception->signature == MagickSignature);
560 separate_image=CloneImage(image,image->columns,image->rows,MagickTrue,
562 if (separate_image == (Image *) NULL)
563 return((Image *) NULL);
564 if (SetImageStorageClass(separate_image,DirectClass,exception) == MagickFalse)
566 separate_image=DestroyImage(separate_image);
567 return((Image *) NULL);
569 separate_image->colorspace=GRAYColorspace;
575 image_view=AcquireCacheView(image);
576 separate_view=AcquireCacheView(separate_image);
577 #if defined(MAGICKCORE_OPENMP_SUPPORT)
578 #pragma omp parallel for schedule(static) shared(progress,status)
580 for (y=0; y < (ssize_t) image->rows; y++)
582 register const Quantum
591 if (status == MagickFalse)
593 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
594 q=QueueCacheViewAuthenticPixels(separate_view,0,y,separate_image->columns,1,
596 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
601 for (x=0; x < (ssize_t) image->columns; x++)
606 if (GetPixelMask(image,p) != 0)
608 p+=GetPixelChannels(image);
609 q+=GetPixelChannels(separate_image);
612 SetPixelChannel(separate_image,GrayPixelChannel,0,q);
613 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
621 channel=GetPixelChannelMapChannel(image,i);
622 traits=GetPixelChannelMapTraits(image,channel);
623 if ((traits == UndefinedPixelTrait) ||
624 (GetChannelBit(channel_type,channel) == 0))
626 SetPixelChannel(separate_image,GrayPixelChannel,p[i],q);
628 p+=GetPixelChannels(image);
629 q+=GetPixelChannels(separate_image);
631 if (SyncCacheViewAuthenticPixels(separate_view,exception) == MagickFalse)
633 if (image->progress_monitor != (MagickProgressMonitor) NULL)
638 #if defined(MAGICKCORE_OPENMP_SUPPORT)
639 #pragma omp critical (MagickCore_SeparateImage)
641 proceed=SetImageProgress(image,SeparateImageTag,progress++,image->rows);
642 if (proceed == MagickFalse)
646 separate_view=DestroyCacheView(separate_view);
647 image_view=DestroyCacheView(image_view);
648 return(separate_image);
652 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
656 % S e p a r a t e I m a g e s %
660 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
662 % SeparateImages() returns a separate grayscale image for each channel
665 % The format of the SeparateImages method is:
667 % MagickBooleanType SeparateImages(const Image *image,
668 % ExceptionInfo *exception)
670 % A description of each parameter follows:
672 % o image: the image.
674 % o exception: return any errors or warnings in this structure.
677 MagickExport Image *SeparateImages(const Image *image,ExceptionInfo *exception)
686 assert(image != (Image *) NULL);
687 assert(image->signature == MagickSignature);
688 if (image->debug != MagickFalse)
689 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
690 images=NewImageList();
691 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
699 channel=GetPixelChannelMapChannel(image,i);
700 traits=GetPixelChannelMapTraits(image,channel);
701 if ((traits == UndefinedPixelTrait) ||
702 ((traits & UpdatePixelTrait) == 0))
704 separate_image=SeparateImage(image,(ChannelType) (1 << channel),exception);
705 if (separate_image != (Image *) NULL)
706 AppendImageToList(&images,separate_image);