1/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3%                                                                             %
4%                                                                             %
5%                                                                             %
6%                         M   M   AAA   SSSSS  K   K                          %
7%                         MM MM  A   A  SS     K  K                           %
8%                         M M M  AAAAA   SSS   KKK                            %
9%                         M   M  A   A     SS  K  K                           %
10%                         M   M  A   A  SSSSS  K   K                          %
11%                                                                             %
12%                                                                             %
13%                              Write Mask File.                               %
14%                                                                             %
15%                              Software Design                                %
16%                                   Cristy                                    %
17%                                 July 1992                                   %
18%                                                                             %
19%                                                                             %
20%  Copyright 1999-2016 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/*
40  Include declarations.
41*/
42#include "MagickCore/studio.h"
43#include "MagickCore/attribute.h"
44#include "MagickCore/blob.h"
45#include "MagickCore/blob-private.h"
46#include "MagickCore/constitute.h"
47#include "MagickCore/enhance.h"
48#include "MagickCore/exception.h"
49#include "MagickCore/exception-private.h"
50#include "MagickCore/list.h"
51#include "MagickCore/magick.h"
52#include "MagickCore/memory_.h"
53#include "MagickCore/monitor.h"
54#include "MagickCore/monitor-private.h"
55#include "MagickCore/pixel-accessor.h"
56#include "MagickCore/quantum-private.h"
57#include "MagickCore/static.h"
58#include "MagickCore/string_.h"
59#include "MagickCore/module.h"
60
61/*
62  Forward declarations.
63*/
64static MagickBooleanType
65  WriteMASKImage(const ImageInfo *,Image *,ExceptionInfo *);
66
67/*
68%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
69%                                                                             %
70%                                                                             %
71%                                                                             %
72%   R e a d M A S K I m a g e                                                 %
73%                                                                             %
74%                                                                             %
75%                                                                             %
76%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
77%
78%  ReadMASKImage returns the image mask associated with the image.
79%
80%  The format of the ReadMASKImage method is:
81%
82%      Image *ReadMASKImage(const ImageInfo *image_info,
83%        ExceptionInfo *exception)
84%
85%  A description of each parameter follows:
86%
87%    o image_info: the image info.
88%
89%    o exception: return any errors or warnings in this structure.
90%
91*/
92static Image *ReadMASKImage(const ImageInfo *image_info,
93  ExceptionInfo *exception)
94{
95  Image
96    *image;
97
98  ImageInfo
99    *read_info;
100
101  /*
102    Initialize Image structure.
103  */
104  assert(image_info != (const ImageInfo *) NULL);
105  assert(image_info->signature == MagickCoreSignature);
106  if (image_info->debug != MagickFalse)
107    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
108      image_info->filename);
109  assert(exception != (ExceptionInfo *) NULL);
110  assert(exception->signature == MagickCoreSignature);
111  read_info=CloneImageInfo(image_info);
112  SetImageInfoBlob(read_info,(void *) NULL,0);
113  (void) CopyMagickString(read_info->magick,"MIFF",MagickPathExtent);
114  image=ReadImage(read_info,exception);
115  read_info=DestroyImageInfo(read_info);
116  if (image != (Image *) NULL)
117    {
118      MagickBooleanType
119        status;
120
121      status=GrayscaleImage(image,image->intensity,exception);
122      if (status == MagickFalse)
123        image=DestroyImage(image);
124    }
125  return(GetFirstImageInList(image));
126}
127
128/*
129%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
130%                                                                             %
131%                                                                             %
132%                                                                             %
133%   R e g i s t e r M A S K I m a g e                                         %
134%                                                                             %
135%                                                                             %
136%                                                                             %
137%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
138%
139%  RegisterMASKImage() adds attributes for the MASK image format to
140%  the list of supported formats.  The attributes include the image format
141%  tag, a method to read and/or write the format, whether the format
142%  supports the saving of more than one frame to the same file or blob,
143%  whether the format supports native in-memory I/O, and a brief
144%  description of the format.
145%
146%  The format of the RegisterMASKImage method is:
147%
148%      size_t RegisterMASKImage(void)
149%
150*/
151ModuleExport size_t RegisterMASKImage(void)
152{
153  MagickInfo
154    *entry;
155
156  entry=AcquireMagickInfo("MASK","MASK","Image Clip Mask");
157  entry->decoder=(DecodeImageHandler *) ReadMASKImage;
158  entry->encoder=(EncodeImageHandler *) WriteMASKImage;
159  (void) RegisterMagickInfo(entry);
160  return(MagickImageCoderSignature);
161}
162
163/*
164%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
165%                                                                             %
166%                                                                             %
167%                                                                             %
168%   U n r e g i s t e r M A S K I m a g e                                     %
169%                                                                             %
170%                                                                             %
171%                                                                             %
172%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
173%
174%  UnregisterMASKImage() removes format registrations made by the
175%  MASK module from the list of supported formats.
176%
177%  The format of the UnregisterMASKImage method is:
178%
179%      UnregisterMASKImage(void)
180%
181*/
182ModuleExport void UnregisterMASKImage(void)
183{
184  (void) UnregisterMagickInfo("MASK");
185}
186
187/*
188%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
189%                                                                             %
190%                                                                             %
191%                                                                             %
192%   W r i t e M A S K I m a g e                                               %
193%                                                                             %
194%                                                                             %
195%                                                                             %
196%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
197%
198%  WriteMASKImage() writes an image mask to a file.
199%
200%  The format of the WriteMASKImage method is:
201%
202%      MagickBooleanType WriteMASKImage(const ImageInfo *image_info,
203%        Image *image,ExceptionInfo *exception)
204%
205%  A description of each parameter follows.
206%
207%    o image_info: the image info.
208%
209%    o image:  The image.
210%
211%    o exception: return any errors or warnings in this structure.
212%
213*/
214
215static Image *MaskImage(const Image *image,ExceptionInfo *exception)
216{
217  CacheView
218    *image_view,
219    *mask_view;
220
221  Image
222    *mask_image;
223
224  MagickBooleanType
225    status;
226
227  ssize_t
228    y;
229
230  mask_image=CloneImage(image,image->columns,image->rows,MagickTrue,
231    exception);
232  if (mask_image == (Image *) NULL)
233    return((Image *) NULL);
234  if (SetImageStorageClass(mask_image,DirectClass,exception) == MagickFalse)
235    {
236      mask_image=DestroyImage(mask_image);
237      return((Image *) NULL);
238    }
239  mask_image->alpha_trait=UndefinedPixelTrait;
240  (void) SetImageColorspace(mask_image,GRAYColorspace,exception);
241  /*
242    Mask image.
243  */
244  status=MagickTrue;
245  image_view=AcquireVirtualCacheView(image,exception);
246  mask_view=AcquireAuthenticCacheView(mask_image,exception);
247  for (y=0; y < (ssize_t) image->rows; y++)
248  {
249    register const Quantum
250      *magick_restrict p;
251
252    register Quantum
253      *magick_restrict q;
254
255    register ssize_t
256      x;
257
258    if (status == MagickFalse)
259      continue;
260    p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
261    q=QueueCacheViewAuthenticPixels(mask_view,0,y,mask_image->columns,1,
262      exception);
263    if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
264      {
265        status=MagickFalse;
266        continue;
267      }
268    for (x=0; x < (ssize_t) image->columns; x++)
269    {
270      SetPixelChannel(mask_image,GrayPixelChannel,0,q);
271      SetPixelChannel(mask_image,GrayPixelChannel,GetPixelReadMask(image,p),q);
272      p+=GetPixelChannels(image);
273      q+=GetPixelChannels(mask_image);
274    }
275    if (SyncCacheViewAuthenticPixels(mask_view,exception) == MagickFalse)
276      status=MagickFalse;
277  }
278  mask_view=DestroyCacheView(mask_view);
279  image_view=DestroyCacheView(image_view);
280  if (status == MagickFalse)
281    mask_image=DestroyImage(mask_image);
282  return(mask_image);
283}
284
285static MagickBooleanType WriteMASKImage(const ImageInfo *image_info,
286  Image *image,ExceptionInfo *exception)
287{
288  Image
289    *mask_image;
290
291  ImageInfo
292    *write_info;
293
294  MagickBooleanType
295    status;
296
297  mask_image=MaskImage(image,exception);
298  if (mask_image == (Image *) NULL)
299    return(MagickFalse);
300  (void) CopyMagickString(mask_image->filename,image->filename,
301    MagickPathExtent);
302  write_info=CloneImageInfo(image_info);
303  *write_info->magick='\0';
304  (void) SetImageInfo(write_info,1,exception);
305  if ((*write_info->magick == '\0') ||
306      (LocaleCompare(write_info->magick,"MASK") == 0))
307    (void) FormatLocaleString(mask_image->filename,MagickPathExtent,"miff:%s",
308      write_info->filename);
309  status=WriteImage(write_info,mask_image,exception);
310  mask_image=DestroyImage(mask_image);
311  write_info=DestroyImageInfo(write_info);
312  return(status);
313}
314