Coverage Report

Created: 2026-06-30 07:12

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/imagemagick/coders/mvg.c
Line
Count
Source
1
/*
2
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3
%                                                                             %
4
%                                                                             %
5
%                                                                             %
6
%                            M   M  V   V   GGGG                              %
7
%                            MM MM  V   V  G                                  %
8
%                            M M M  V   V  G GG                               %
9
%                            M   M   V V   G   G                              %
10
%                            M   M    V     GGG                               %
11
%                                                                             %
12
%                                                                             %
13
%                 Read/Write Magick Vector Graphics Metafiles.                %
14
%                                                                             %
15
%                              Software Design                                %
16
%                                   Cristy                                    %
17
%                                 April 2000                                  %
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/artifact.h"
44
#include "MagickCore/blob.h"
45
#include "MagickCore/blob-private.h"
46
#include "MagickCore/draw.h"
47
#include "MagickCore/exception.h"
48
#include "MagickCore/exception-private.h"
49
#include "MagickCore/image.h"
50
#include "MagickCore/image-private.h"
51
#include "MagickCore/list.h"
52
#include "MagickCore/magick.h"
53
#include "MagickCore/memory_.h"
54
#include "MagickCore/module.h"
55
#include "MagickCore/property.h"
56
#include "MagickCore/quantum-private.h"
57
#include "MagickCore/static.h"
58
#include "MagickCore/string_.h"
59
#include "MagickCore/string-private.h"
60

61
/*
62
  Forward declarations.
63
*/
64
static MagickBooleanType
65
  WriteMVGImage(const ImageInfo *,Image *,ExceptionInfo *);
66

67
/*
68
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
69
%                                                                             %
70
%                                                                             %
71
%                                                                             %
72
%   I s M V G                                                                 %
73
%                                                                             %
74
%                                                                             %
75
%                                                                             %
76
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
77
%
78
%  IsMVG() returns MagickTrue if the image format type, identified by the
79
%  magick string, is MVG.
80
%
81
%  The format of the IsMVG method is:
82
%
83
%      MagickBooleanType IsMVG(const unsigned char *magick,const size_t length)
84
%
85
%  A description of each parameter follows:
86
%
87
%    o magick: compare image format pattern against these bytes.
88
%
89
%    o length: Specifies the length of the magick string.
90
%
91
*/
92
static MagickBooleanType IsMVG(const unsigned char *magick,const size_t length)
93
0
{
94
0
  if (length < 20)
95
0
    return(MagickFalse);
96
0
  if (LocaleNCompare((const char *) magick,"push graphic-context",20) == 0)
97
0
    return(MagickTrue);
98
0
  return(MagickFalse);
99
0
}
100

101
/*
102
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
103
%                                                                             %
104
%                                                                             %
105
%                                                                             %
106
%   R e a d M V G I m a g e                                                   %
107
%                                                                             %
108
%                                                                             %
109
%                                                                             %
110
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
111
%
112
%  ReadMVGImage creates a gradient image and initializes it to
113
%  the X server color range as specified by the filename.  It allocates the
114
%  memory necessary for the new Image structure and returns a pointer to the
115
%  new image.
116
%
117
%  The format of the ReadMVGImage method is:
118
%
119
%      Image *ReadMVGImage(const ImageInfo *image_info,ExceptionInfo *exception)
120
%
121
%  A description of each parameter follows:
122
%
123
%    o image_info: the image info.
124
%
125
%    o exception: return any errors or warnings in this structure.
126
%
127
*/
128
static Image *ReadMVGImage(const ImageInfo *image_info,ExceptionInfo *exception)
129
2.92k
{
130
2.92k
  DrawInfo
131
2.92k
    *draw_info;
132
133
2.92k
  Image
134
2.92k
    *image;
135
136
2.92k
  MagickBooleanType
137
2.92k
    status;
138
139
  /*
140
    Open image.
141
  */
142
2.92k
  assert(image_info != (const ImageInfo *) NULL);
143
2.92k
  assert(image_info->signature == MagickCoreSignature);
144
2.92k
  assert(exception != (ExceptionInfo *) NULL);
145
2.92k
  assert(exception->signature == MagickCoreSignature);
146
2.92k
  if (IsEventLogging() != MagickFalse)
147
0
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
148
0
      image_info->filename);
149
2.92k
  image=AcquireImage(image_info,exception);
150
2.92k
  status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
151
2.92k
  if (status == MagickFalse)
152
0
    {
153
0
      image=DestroyImageList(image);
154
0
      return((Image *) NULL);
155
0
    }
156
2.92k
  if ((image->columns == 0) || (image->rows == 0))
157
2.92k
    {
158
2.92k
      char
159
2.92k
        primitive[MagickPathExtent];
160
161
2.92k
      char
162
2.92k
        *p;
163
164
2.92k
      SegmentInfo
165
2.92k
        bounds;
166
167
      /*
168
        Determine size of image canvas.
169
      */
170
2.92k
      (void) memset(&bounds,0,sizeof(bounds));
171
13.9k
      while (ReadBlobString(image,primitive) != (char *) NULL)
172
13.9k
      {
173
13.9k
        int
174
13.9k
          count;
175
176
20.3k
        for (p=primitive; (*p == ' ') || (*p == '\t'); p++) ;
177
13.9k
        count=MagickSscanf(p,"viewbox %lf %lf %lf %lf",&bounds.x1,&bounds.y1,
178
13.9k
          &bounds.x2,&bounds.y2);
179
13.9k
        if (count != 4)
180
11.0k
          continue;
181
2.90k
        image->columns=CastDoubleToSizeT(floor((bounds.x2-bounds.x1)+0.5));
182
2.90k
        image->rows=CastDoubleToSizeT(floor((bounds.y2-bounds.y1)+0.5));
183
2.90k
        break;
184
13.9k
      }
185
2.92k
    }
186
2.92k
  if ((image->columns == 0) || (image->rows == 0))
187
2.90k
    ThrowReaderException(OptionError,"MustSpecifyImageSize");
188
2.90k
  draw_info=CloneDrawInfo(image_info,(DrawInfo *) NULL);
189
2.90k
  if (draw_info->density != (char *) NULL)
190
0
    draw_info->density=DestroyString(draw_info->density);
191
2.90k
  draw_info->affine.sx=image->resolution.x == 0.0 ? 1.0 : image->resolution.x/
192
0
    96.0;
193
2.90k
  draw_info->affine.sy=image->resolution.y == 0.0 ? 1.0 : image->resolution.y/
194
0
    96.0;
195
2.90k
  image->columns=CastDoubleToSizeT(draw_info->affine.sx*image->columns);
196
2.90k
  image->rows=CastDoubleToSizeT(draw_info->affine.sy*image->rows);
197
2.90k
  status=SetImageExtent(image,image->columns,image->rows,exception);
198
2.90k
  if (status == MagickFalse)
199
1
    {
200
1
      draw_info=DestroyDrawInfo(draw_info);
201
1
      return(DestroyImageList(image));
202
1
    }
203
2.90k
  if (SetImageBackgroundColor(image,exception) == MagickFalse)
204
0
    {
205
0
      draw_info=DestroyDrawInfo(draw_info);
206
0
      return(DestroyImageList(image));
207
0
    }
208
  /*
209
    Render drawing.
210
  */
211
2.90k
  if (GetBlobStreamData(image) == (unsigned char *) NULL)
212
0
    draw_info->primitive=FileToString(image->filename,~0UL,exception);
213
2.90k
  else
214
2.90k
    {
215
2.90k
      MagickSizeType
216
2.90k
        length;
217
218
2.90k
      length=GetBlobSize(image);
219
2.90k
      if (length == (MagickSizeType) ((size_t) length))
220
2.90k
        {
221
2.90k
          draw_info->primitive=(char *) AcquireQuantumMemory(1,(size_t) length+1);
222
2.90k
          if (draw_info->primitive != (char *) NULL)
223
2.90k
            {
224
2.90k
              memcpy(draw_info->primitive,GetBlobStreamData(image),(size_t)
225
2.90k
                length);
226
2.90k
              draw_info->primitive[length]='\0';
227
2.90k
            }
228
2.90k
         }
229
2.90k
     }
230
2.90k
  if (draw_info->primitive == (char *) NULL)
231
0
    {
232
0
      draw_info=DestroyDrawInfo(draw_info);
233
0
      return(DestroyImageList(image));
234
0
    }
235
2.90k
  if (*draw_info->primitive == '@')
236
0
    {
237
0
      draw_info=DestroyDrawInfo(draw_info);
238
0
      ThrowReaderException(CorruptImageError,"ImproperImageHeader");
239
0
    }
240
2.90k
  (void) DrawImage(image,draw_info,exception);
241
2.90k
  (void) SetImageArtifact(image,"mvg:vector-graphics",draw_info->primitive);
242
2.90k
  draw_info=DestroyDrawInfo(draw_info);
243
2.90k
  if (CloseBlob(image) == MagickFalse)
244
0
    status=MagickFalse;
245
2.90k
  if (status == MagickFalse)
246
0
    return(DestroyImageList(image));
247
2.90k
  return(GetFirstImageInList(image));
248
2.90k
}
249

250
/*
251
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
252
%                                                                             %
253
%                                                                             %
254
%                                                                             %
255
%   R e g i s t e r M V G I m a g e                                           %
256
%                                                                             %
257
%                                                                             %
258
%                                                                             %
259
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
260
%
261
%  RegisterMVGImage() adds properties for the MVG image format
262
%  to the list of supported formats.  The properties include the image format
263
%  tag, a method to read and/or write the format, whether the format
264
%  supports the saving of more than one frame to the same file or blob,
265
%  whether the format supports native in-memory I/O, and a brief
266
%  description of the format.
267
%
268
%  The format of the RegisterMVGImage method is:
269
%
270
%      size_t RegisterMVGImage(void)
271
%
272
*/
273
ModuleExport size_t RegisterMVGImage(void)
274
8
{
275
8
  MagickInfo
276
8
    *entry;
277
278
8
  entry=AcquireMagickInfo("MVG","MVG","Magick Vector Graphics");
279
8
  entry->decoder=(DecodeImageHandler *) ReadMVGImage;
280
8
  entry->encoder=(EncodeImageHandler *) WriteMVGImage;
281
8
  entry->magick=(IsImageFormatHandler *) IsMVG;
282
8
  entry->format_type=ImplicitFormatType;
283
8
  entry->flags|=CoderDecoderSeekableStreamFlag;
284
8
  entry->flags^=CoderAdjoinFlag;
285
8
  (void) RegisterMagickInfo(entry);
286
8
  return(MagickImageCoderSignature);
287
8
}
288

289
/*
290
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
291
%                                                                             %
292
%                                                                             %
293
%                                                                             %
294
%   U n r e g i s t e r M V G I m a g e                                       %
295
%                                                                             %
296
%                                                                             %
297
%                                                                             %
298
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
299
%
300
%  UnregisterMVGImage() removes format registrations made by the
301
%  MVG module from the list of supported formats.
302
%
303
%  The format of the UnregisterMVGImage method is:
304
%
305
%      UnregisterMVGImage(void)
306
%
307
*/
308
ModuleExport void UnregisterMVGImage(void)
309
0
{
310
0
  (void) UnregisterMagickInfo("MVG");
311
0
}
312

313
/*
314
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
315
%                                                                             %
316
%                                                                             %
317
%                                                                             %
318
%   W r i t e M V G I m a g e                                                 %
319
%                                                                             %
320
%                                                                             %
321
%                                                                             %
322
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
323
%
324
%  WriteMVGImage() writes an image to a file in MVG image format.
325
%
326
%  The format of the WriteMVGImage method is:
327
%
328
%      MagickBooleanType WriteMVGImage(const ImageInfo *image_info,
329
%        Image *image,ExceptionInfo *exception)
330
%
331
%  A description of each parameter follows.
332
%
333
%    o image_info: the image info.
334
%
335
%    o image:  The image.
336
%
337
%    o exception: return any errors or warnings in this structure.
338
%
339
*/
340
static MagickBooleanType WriteMVGImage(const ImageInfo *image_info,Image *image,
341
  ExceptionInfo *exception)
342
60
{
343
60
  const char
344
60
    *value;
345
346
60
  MagickBooleanType
347
60
    status;
348
349
  /*
350
    Open output image file.
351
  */
352
60
  assert(image_info != (const ImageInfo *) NULL);
353
60
  assert(image_info->signature == MagickCoreSignature);
354
60
  assert(image != (Image *) NULL);
355
60
  assert(image->signature == MagickCoreSignature);
356
60
  if (IsEventLogging() != MagickFalse)
357
0
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
358
60
  value=GetImageArtifact(image,"mvg:vector-graphics");
359
60
  if (value == (const char *) NULL)
360
60
    ThrowWriterException(OptionError,"NoImageVectorGraphics");
361
60
  status=OpenBlob(image_info,image,WriteBlobMode,exception);
362
60
  if (status == MagickFalse)
363
0
    return(status);
364
60
  (void) WriteBlob(image,strlen(value),(const unsigned char *) value);
365
60
  if (CloseBlob(image) == MagickFalse)
366
0
    status=MagickFalse;
367
60
  return(status);
368
60
}