Coverage Report

Created: 2026-02-14 07:11

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/imagemagick/coders/mask.c
Line
Count
Source
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 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/license/                                         %
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/property.h"
57
#include "MagickCore/quantum-private.h"
58
#include "MagickCore/static.h"
59
#include "MagickCore/string_.h"
60
#include "MagickCore/module.h"
61

62
/*
63
  Forward declarations.
64
*/
65
static MagickBooleanType
66
  WriteMASKImage(const ImageInfo *,Image *,ExceptionInfo *);
67

68
/*
69
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
70
%                                                                             %
71
%                                                                             %
72
%                                                                             %
73
%   R e a d M A S K I m a g e                                                 %
74
%                                                                             %
75
%                                                                             %
76
%                                                                             %
77
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
78
%
79
%  ReadMASKImage returns the image mask associated with the image.
80
%
81
%  The format of the ReadMASKImage method is:
82
%
83
%      Image *ReadMASKImage(const ImageInfo *image_info,
84
%        ExceptionInfo *exception)
85
%
86
%  A description of each parameter follows:
87
%
88
%    o image_info: the image info.
89
%
90
%    o exception: return any errors or warnings in this structure.
91
%
92
*/
93
static Image *ReadMASKImage(const ImageInfo *image_info,
94
  ExceptionInfo *exception)
95
51
{
96
51
  Image
97
51
    *image;
98
99
51
  ImageInfo
100
51
    *read_info;
101
102
  /*
103
    Initialize Image structure.
104
  */
105
51
  assert(image_info != (const ImageInfo *) NULL);
106
51
  assert(image_info->signature == MagickCoreSignature);
107
51
  assert(exception != (ExceptionInfo *) NULL);
108
51
  assert(exception->signature == MagickCoreSignature);
109
51
  if (IsEventLogging() != MagickFalse)
110
0
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
111
0
      image_info->filename);
112
51
  read_info=CloneImageInfo(image_info);
113
51
  SetImageInfoBlob(read_info,(void *) NULL,0);
114
51
  (void) FormatLocaleString(read_info->filename,MagickPathExtent,
115
51
    "miff:%s",image_info->filename);
116
51
  image=ReadImage(read_info,exception);
117
51
  read_info=DestroyImageInfo(read_info);
118
51
  if (image != (Image *) NULL)
119
0
    {
120
0
      MagickBooleanType
121
0
        status;
122
123
0
      status=GrayscaleImage(image,image->intensity,exception);
124
0
      if (status == MagickFalse)
125
0
        image=DestroyImage(image);
126
0
    }
127
51
  return(GetFirstImageInList(image));
128
51
}
129

130
/*
131
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
132
%                                                                             %
133
%                                                                             %
134
%                                                                             %
135
%   R e g i s t e r M A S K I m a g e                                         %
136
%                                                                             %
137
%                                                                             %
138
%                                                                             %
139
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
140
%
141
%  RegisterMASKImage() adds attributes for the MASK image format to
142
%  the list of supported formats.  The attributes include the image format
143
%  tag, a method to read and/or write the format, whether the format
144
%  supports the saving of more than one frame to the same file or blob,
145
%  whether the format supports native in-memory I/O, and a brief
146
%  description of the format.
147
%
148
%  The format of the RegisterMASKImage method is:
149
%
150
%      size_t RegisterMASKImage(void)
151
%
152
*/
153
ModuleExport size_t RegisterMASKImage(void)
154
8
{
155
8
  MagickInfo
156
8
    *entry;
157
158
8
  entry=AcquireMagickInfo("MASK","MASK","Image Clip Mask");
159
8
  entry->decoder=(DecodeImageHandler *) ReadMASKImage;
160
8
  entry->encoder=(EncodeImageHandler *) WriteMASKImage;
161
8
  (void) RegisterMagickInfo(entry);
162
8
  return(MagickImageCoderSignature);
163
8
}
164

165
/*
166
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
167
%                                                                             %
168
%                                                                             %
169
%                                                                             %
170
%   U n r e g i s t e r M A S K I m a g e                                     %
171
%                                                                             %
172
%                                                                             %
173
%                                                                             %
174
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
175
%
176
%  UnregisterMASKImage() removes format registrations made by the
177
%  MASK module from the list of supported formats.
178
%
179
%  The format of the UnregisterMASKImage method is:
180
%
181
%      UnregisterMASKImage(void)
182
%
183
*/
184
ModuleExport void UnregisterMASKImage(void)
185
0
{
186
0
  (void) UnregisterMagickInfo("MASK");
187
0
}
188

189
/*
190
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
191
%                                                                             %
192
%                                                                             %
193
%                                                                             %
194
%   W r i t e M A S K I m a g e                                               %
195
%                                                                             %
196
%                                                                             %
197
%                                                                             %
198
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
199
%
200
%  WriteMASKImage() writes an image mask to a file.
201
%
202
%  The format of the WriteMASKImage method is:
203
%
204
%      MagickBooleanType WriteMASKImage(const ImageInfo *image_info,
205
%        Image *image,ExceptionInfo *exception)
206
%
207
%  A description of each parameter follows.
208
%
209
%    o image_info: the image info.
210
%
211
%    o image:  The image.
212
%
213
%    o exception: return any errors or warnings in this structure.
214
%
215
*/
216
217
static Image *MaskImage(const Image *image,const PixelChannel mask_channel,
218
  ExceptionInfo *exception)
219
0
{
220
0
  CacheView
221
0
    *image_view,
222
0
    *mask_view;
223
224
0
  Image
225
0
    *mask_image;
226
227
0
  MagickBooleanType
228
0
    status;
229
230
0
  ssize_t
231
0
    y;
232
233
0
  mask_image=CloneImage(image,0,0,MagickTrue,exception);
234
0
  if (mask_image == (Image *) NULL)
235
0
    return((Image *) NULL);
236
0
  if (SetImageStorageClass(mask_image,DirectClass,exception) == MagickFalse)
237
0
    {
238
0
      mask_image=DestroyImage(mask_image);
239
0
      return((Image *) NULL);
240
0
    }
241
0
  mask_image->alpha_trait=UndefinedPixelTrait;
242
0
  (void) SetImageColorspace(mask_image,GRAYColorspace,exception);
243
  /*
244
    Mask image.
245
  */
246
0
  status=MagickTrue;
247
0
  image_view=AcquireVirtualCacheView(image,exception);
248
0
  mask_view=AcquireAuthenticCacheView(mask_image,exception);
249
0
  for (y=0; y < (ssize_t) image->rows; y++)
250
0
  {
251
0
    const Quantum
252
0
      *magick_restrict p;
253
254
0
    Quantum
255
0
      *magick_restrict q;
256
257
0
    ssize_t
258
0
      x;
259
260
0
    if (status == MagickFalse)
261
0
      continue;
262
0
    p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
263
0
    q=QueueCacheViewAuthenticPixels(mask_view,0,y,mask_image->columns,1,
264
0
      exception);
265
0
    if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
266
0
      {
267
0
        status=MagickFalse;
268
0
        continue;
269
0
      }
270
0
    for (x=0; x < (ssize_t) image->columns; x++)
271
0
    {
272
0
      switch (mask_channel)
273
0
      {
274
0
        case CompositeMaskPixelChannel:
275
0
        {
276
0
          SetPixelChannel(mask_image,GrayPixelChannel,
277
0
            GetPixelCompositeMask(image,p),q);
278
0
          break;
279
0
        }
280
0
        case ReadMaskPixelChannel:
281
0
        {
282
0
          SetPixelChannel(mask_image,GrayPixelChannel,
283
0
            GetPixelReadMask(image,p),q);
284
0
          break;
285
0
        }
286
0
        case WriteMaskPixelChannel:
287
0
        {
288
0
          SetPixelChannel(mask_image,GrayPixelChannel,
289
0
            GetPixelWriteMask(image,p),q);
290
0
          break;
291
0
        }
292
0
        default:
293
0
        {
294
0
          SetPixelChannel(mask_image,GrayPixelChannel,0,q);
295
0
          break;
296
0
        }
297
0
      }
298
0
      p+=(ptrdiff_t) GetPixelChannels(image);
299
0
      q+=(ptrdiff_t) GetPixelChannels(mask_image);
300
0
    }
301
0
    if (SyncCacheViewAuthenticPixels(mask_view,exception) == MagickFalse)
302
0
      status=MagickFalse;
303
0
  }
304
0
  mask_view=DestroyCacheView(mask_view);
305
0
  image_view=DestroyCacheView(image_view);
306
0
  if (status == MagickFalse)
307
0
    mask_image=DestroyImage(mask_image);
308
0
  return(mask_image);
309
0
}
310
311
static MagickBooleanType WriteMASKImage(const ImageInfo *image_info,
312
  Image *image,ExceptionInfo *exception)
313
0
{
314
0
  Image
315
0
    *mask_image,
316
0
    *write_image;
317
318
0
  ImageInfo
319
0
    *write_info;
320
321
0
  MagickBooleanType
322
0
    status;
323
324
0
  write_image=NewImageList();
325
0
  if (GetPixelWriteMaskTraits(image) != UndefinedPixelTrait)
326
0
    {
327
0
      mask_image=MaskImage(image,WriteMaskPixelChannel,exception);
328
0
      if (mask_image != (Image *) NULL)
329
0
        {
330
0
          (void) SetImageProperty(image,"mask","write",exception);
331
0
          AppendImageToList(&write_image,mask_image);
332
0
        }
333
0
    }
334
0
  if (GetPixelReadMaskTraits(image) != UndefinedPixelTrait)
335
0
    {
336
0
      mask_image=MaskImage(image,ReadMaskPixelChannel,exception);
337
0
      if (mask_image != (Image *) NULL)
338
0
        {
339
0
          (void) SetImageProperty(image,"mask","read",exception);
340
0
          AppendImageToList(&write_image,mask_image);
341
0
        }
342
0
    }
343
0
  if (GetPixelCompositeMaskTraits(image) != UndefinedPixelTrait)
344
0
    {
345
0
      mask_image=MaskImage(image,CompositeMaskPixelChannel,exception);
346
0
      if (mask_image != (Image *) NULL)
347
0
        {
348
0
          (void) SetImageProperty(image,"mask","composite",exception);
349
0
          AppendImageToList(&write_image,mask_image);
350
0
        }
351
0
    }
352
0
  if (write_image == (Image *) NULL)
353
0
    ThrowWriterException(CoderError,"ImageDoesNotHaveAMaskChannel");
354
0
  (void) CopyMagickString(write_image->filename,image->filename,
355
0
    MagickPathExtent);
356
0
  write_info=CloneImageInfo(image_info);
357
0
  *write_info->magick='\0';
358
0
  (void) SetImageInfo(write_info,1,exception);
359
0
  if ((*write_info->magick == '\0') ||
360
0
      (LocaleCompare(write_info->magick,"MASK") == 0))
361
0
    (void) FormatLocaleString(write_image->filename,MagickPathExtent,"miff:%s",
362
0
      write_info->filename);
363
0
  status=WriteImage(write_info,write_image,exception);
364
0
  write_image=DestroyImage(write_image);
365
0
  write_info=DestroyImageInfo(write_info);
366
0
  return(status);
367
0
}