]> granicus.if.org Git - imagemagick/blob - MagickCore/channel.c
(no commit message)
[imagemagick] / MagickCore / 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  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               %
11 %                                                                             %
12 %                                                                             %
13 %                      MagickCore Image Channel Methods                       %
14 %                                                                             %
15 %                              Software Design                                %
16 %                                John Cristy                                  %
17 %                               December 2003                                 %
18 %                                                                             %
19 %                                                                             %
20 %  Copyright 1999-2012 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 %    http://www.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 \f
40 /*
41   Include declarations.
42 */
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"
54 \f
55 /*
56 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
57 %                                                                             %
58 %                                                                             %
59 %                                                                             %
60 %     C h a n n e l O p e r a t i o n I m a g e                               %
61 %                                                                             %
62 %                                                                             %
63 %                                                                             %
64 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
65 %
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:
69 %
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)
75 %
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:
78 %
79 %    -channel-ops "red; green; blue"
80 %
81 %  The format of the ChannelOperationImage method is:
82 %
83 %      Image *ChannelOperationImage(const Image *image,
84 %        const char *expression,ExceptionInfo *exception)
85 %
86 %  A description of each parameter follows:
87 %
88 %    o image: the image.
89 %
90 %    o expression: A channel expression.
91 %
92 %    o exception: return any errors or warnings in this structure.
93 %
94 */
95
96 typedef enum
97 {
98   ExtractChannelOp,
99   ExchangeChannelOp,
100   TransferChannelOp
101 } ChannelOperation;
102
103 static inline size_t MagickMin(const size_t x,const size_t y)
104 {
105   if (x < y)
106     return(x);
107   return(y);
108 }
109
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)
114 {
115   CacheView
116     *source_view,
117     *destination_view;
118
119   MagickBooleanType
120     status;
121
122   size_t
123     height;
124
125   ssize_t
126     y;
127
128   status=MagickTrue;
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)
134 #endif
135   for (y=0; y < (ssize_t) height; y++)
136   {
137     register const Quantum
138       *restrict p;
139
140     register Quantum
141       *restrict q;
142
143     register ssize_t
144       x;
145
146     size_t
147       width;
148
149     if (status == MagickFalse)
150       continue;
151     p=GetCacheViewVirtualPixels(source_view,0,y,source_image->columns,1,
152       exception);
153     q=QueueCacheViewAuthenticPixels(destination_view,0,y,
154       destination_image->columns,1,exception);
155     if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
156       {
157         status=MagickFalse;
158         continue;
159       }
160     width=MagickMin(source_image->columns,destination_image->columns);
161     for (x=0; x < (ssize_t) width; x++)
162     {
163       PixelTrait
164         destination_traits,
165         source_traits;
166
167       ssize_t
168         offset;
169
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))
175         continue;
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);
180     }
181     if (SyncCacheViewAuthenticPixels(destination_view,exception) == MagickFalse)
182       status=MagickFalse;
183   }
184   destination_view=DestroyCacheView(destination_view);
185   source_view=DestroyCacheView(source_view);
186   return(status);
187 }
188
189 MagickExport Image *ChannelOperationImage(const Image *image,
190   const char *expression,ExceptionInfo *exception)
191 {
192 #define ChannelOperationImageTag  "ChannelOperation/Image"
193
194   char
195     token[MaxTextExtent];
196
197   ChannelOperation
198     channel_op;
199
200   const char
201     *p;
202
203   const Image
204     *source_image;
205
206   Image
207     *destination_image;
208
209   PixelChannel
210     source_channel,
211     destination_channel;
212
213   ssize_t
214     channels;
215
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);
222   source_image=image;
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)
227     {
228       destination_image=GetLastImageInList(destination_image);
229       return((Image *) NULL);
230     }
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'; )
237   {
238     MagickBooleanType
239       status;
240
241     ssize_t
242       i;
243
244     /*
245       Interpret channel expression.
246     */
247     if (*token == ',')
248       {
249         destination_channel=(PixelChannel) ((ssize_t) destination_channel+1);
250         GetMagickToken(p,&p,token);
251       }
252     if (*token == '|')
253       {
254         if (GetNextImageInList(source_image) != (Image *) NULL)
255           source_image=GetNextImageInList(source_image);
256         else
257           source_image=GetFirstImageInList(source_image);
258         GetMagickToken(p,&p,token);
259       }
260     if (*token == ';')
261       {
262         Image
263           *canvas;
264
265         if (channels == 1)
266           destination_image->colorspace=GRAYColorspace;
267         canvas=CloneImage(source_image,0,0,MagickTrue,exception);
268         if (canvas == (Image *) NULL)
269           {
270             destination_image=GetLastImageInList(destination_image);
271             return((Image *) NULL);
272           }
273         AppendImageToList(&destination_image,canvas);
274         destination_image=GetLastImageInList(destination_image);
275         if (SetImageBackgroundColor(destination_image,exception) == MagickFalse)
276           {
277             destination_image=GetLastImageInList(destination_image);
278             return((Image *) NULL);
279           }
280         GetMagickToken(p,&p,token);
281         channels=0;
282         destination_channel=RedPixelChannel;
283       }
284     i=ParsePixelChannelOption(token);
285     if (i < 0)
286       {
287         (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
288           "UnableToParseExpression","`%s'",p);
289         destination_image=DestroyImageList(destination_image);
290         break;
291       }
292     source_channel=(PixelChannel) i;
293     channel_op=ExtractChannelOp;
294     GetMagickToken(p,&p,token);
295     if (*token == '<')
296       {
297         channel_op=ExchangeChannelOp;
298         GetMagickToken(p,&p,token);
299       }
300     if (*token == '=')
301       GetMagickToken(p,&p,token);
302     if (*token == '>')
303       {
304         if (channel_op != ExchangeChannelOp)
305           channel_op=TransferChannelOp;
306         GetMagickToken(p,&p,token);
307       }
308     if (channel_op != ExtractChannelOp)
309       {
310         i=ParsePixelChannelOption(token);
311         if (i < 0)
312           {
313             (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
314               "UnableToParseExpression","`%s'",p);
315             destination_image=DestroyImageList(destination_image);
316             break;
317           }
318         destination_channel=(PixelChannel) i;
319       }
320     status=ChannelImage(destination_image,source_image,channel_op,
321       source_channel,destination_channel,exception);
322     if (status == MagickFalse)
323       {
324         destination_image=DestroyImageList(destination_image);
325         break;
326       }
327     channels++;
328     status=SetImageProgress(source_image,ChannelOperationImageTag,p-expression,
329       strlen(expression));
330     if (status == MagickFalse)
331       break;
332   }
333   if (channels == 1)
334     destination_image->colorspace=GRAYColorspace;
335   return(destination_image);
336 }