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 O p e r a t i o n I m a g e %
64 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
66 % ChannelOperationImage() applies a channel expression to the specified image.
67 % The expression consists of one or more channels, either mnemonic or numeric
68 % (e.g. red, 1), separated by certain operation symbols 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-ops "red; green; blue"
81 % The format of the ChannelOperationImage method is:
83 % Image *ChannelOperationImage(const Image *image,
84 % const char *expression,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 ChannelOperation 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 *ChannelOperationImage(const Image *image,
190 const char *expression,ExceptionInfo *exception)
192 #define ChannelOperationImageTag "ChannelOperation/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);
266 destination_image->colorspace=GRAYColorspace;
267 canvas=CloneImage(source_image,0,0,MagickTrue,exception);
268 if (canvas == (Image *) NULL)
270 destination_image=GetLastImageInList(destination_image);
271 return((Image *) NULL);
273 AppendImageToList(&destination_image,canvas);
274 destination_image=GetLastImageInList(destination_image);
275 if (SetImageBackgroundColor(destination_image,exception) == MagickFalse)
277 destination_image=GetLastImageInList(destination_image);
278 return((Image *) NULL);
280 GetMagickToken(p,&p,token);
282 destination_channel=RedPixelChannel;
284 i=ParsePixelChannelOption(token);
287 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
288 "UnableToParseExpression","`%s'",p);
289 destination_image=DestroyImageList(destination_image);
292 source_channel=(PixelChannel) i;
293 channel_op=ExtractChannelOp;
294 GetMagickToken(p,&p,token);
297 channel_op=ExchangeChannelOp;
298 GetMagickToken(p,&p,token);
301 GetMagickToken(p,&p,token);
304 if (channel_op != ExchangeChannelOp)
305 channel_op=TransferChannelOp;
306 GetMagickToken(p,&p,token);
308 if (channel_op != ExtractChannelOp)
310 i=ParsePixelChannelOption(token);
313 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
314 "UnableToParseExpression","`%s'",p);
315 destination_image=DestroyImageList(destination_image);
318 destination_channel=(PixelChannel) i;
320 status=ChannelImage(destination_image,source_image,channel_op,
321 source_channel,destination_channel,exception);
322 if (status == MagickFalse)
324 destination_image=DestroyImageList(destination_image);
328 status=SetImageProgress(source_image,ChannelOperationImageTag,p-expression,
330 if (status == MagickFalse)
334 destination_image->colorspace=GRAYColorspace;
335 return(destination_image);