Coverage Report

Created: 2026-02-14 07:11

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/imagemagick/coders/xps.c
Line
Count
Source
1
/*
2
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3
%                                                                             %
4
%                                                                             %
5
%                                                                             %
6
%                            X   X  PPPP   SSSSS                              %
7
%                             X X   P   P  SS                                 %
8
%                              X    PPPP    SSS                               %
9
%                             X X   P         SS                              %
10
%                            X   X  P      SSSSS                              %
11
%                                                                             %
12
%                                                                             %
13
%             Read/Write Microsoft XML Paper Specification Format             %
14
%                                                                             %
15
%                              Software Design                                %
16
%                                   Cristy                                    %
17
%                                January 2008                                 %
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/attribute.h"
45
#include "MagickCore/blob.h"
46
#include "MagickCore/blob-private.h"
47
#include "MagickCore/cache.h"
48
#include "MagickCore/color.h"
49
#include "MagickCore/color-private.h"
50
#include "MagickCore/colorspace.h"
51
#include "MagickCore/colorspace-private.h"
52
#include "MagickCore/constitute.h"
53
#include "MagickCore/delegate.h"
54
#include "MagickCore/delegate-private.h"
55
#include "MagickCore/draw.h"
56
#include "MagickCore/exception.h"
57
#include "MagickCore/exception-private.h"
58
#include "MagickCore/geometry.h"
59
#include "MagickCore/image.h"
60
#include "MagickCore/image-private.h"
61
#include "MagickCore/list.h"
62
#include "MagickCore/magick.h"
63
#include "MagickCore/memory_.h"
64
#include "MagickCore/module.h"
65
#include "MagickCore/monitor.h"
66
#include "MagickCore/monitor-private.h"
67
#include "MagickCore/nt-base-private.h"
68
#include "MagickCore/option.h"
69
#include "MagickCore/profile.h"
70
#include "MagickCore/resource_.h"
71
#include "MagickCore/pixel-accessor.h"
72
#include "MagickCore/property.h"
73
#include "MagickCore/quantum-private.h"
74
#include "MagickCore/static.h"
75
#include "MagickCore/string_.h"
76
#include "MagickCore/string-private.h"
77
#include "MagickCore/timer-private.h"
78
#include "MagickCore/token.h"
79
#include "MagickCore/transform.h"
80
#include "MagickCore/utility.h"
81
#include "coders/bytebuffer-private.h"
82
#include "coders/ghostscript-private.h"
83

84
/*
85
  Typedef declarations.
86
*/
87
typedef struct _XPSInfo
88
{
89
  MagickBooleanType
90
    cmyk;
91
92
  SegmentInfo
93
    bounds;
94
95
  unsigned long
96
    columns,
97
    rows;
98
99
  StringInfo
100
    *icc_profile,
101
    *photoshop_profile,
102
    *xmp_profile;
103
} XPSInfo;
104

105
/*
106
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
107
%                                                                             %
108
%                                                                             %
109
%                                                                             %
110
%   R e a d X P S I m a g e                                                   %
111
%                                                                             %
112
%                                                                             %
113
%                                                                             %
114
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
115
%
116
%  ReadXPSImage() reads a Printer Control Language image file and returns it.
117
%  It allocates the memory necessary for the new Image structure and returns a
118
%  pointer to the new image.
119
%
120
%  The format of the ReadPSImage method is:
121
%
122
%      Image *ReadPSImage(const ImageInfo *image_info,ExceptionInfo *exception)
123
%
124
%  A description of each parameter follows:
125
%
126
%    o image_info: the image info.
127
%
128
%    o exception: return any errors or warnings in this structure.
129
%
130
*/
131
132
static Image *ReadXPSImage(const ImageInfo *image_info,ExceptionInfo *exception)
133
257
{
134
257
  char
135
257
    command[MagickPathExtent],
136
257
    *density,
137
257
    filename[MagickPathExtent],
138
257
    input_filename[MagickPathExtent],
139
257
    message[MagickPathExtent],
140
257
    *options;
141
142
257
  const char
143
257
    *option;
144
145
257
  const DelegateInfo
146
257
    *delegate_info;
147
148
257
  GeometryInfo
149
257
    geometry_info;
150
151
257
  Image
152
257
    *image,
153
257
    *next,
154
257
    *postscript_image;
155
156
257
  ImageInfo
157
257
    *read_info;
158
159
257
  MagickBooleanType
160
257
    fitPage,
161
257
    status;
162
163
257
  MagickStatusType
164
257
    flags;
165
166
257
  PointInfo
167
257
    delta,
168
257
    resolution;
169
170
257
  RectangleInfo
171
257
    page;
172
173
257
  ssize_t
174
257
    i;
175
176
257
  unsigned long
177
257
    scene;
178
179
  /*
180
    Open image file.
181
  */
182
257
  assert(image_info != (const ImageInfo *) NULL);
183
257
  assert(image_info->signature == MagickCoreSignature);
184
257
  assert(exception != (ExceptionInfo *) NULL);
185
257
  assert(exception->signature == MagickCoreSignature);
186
257
  if (IsEventLogging() != MagickFalse)
187
0
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
188
0
      image_info->filename);
189
257
  image=AcquireImage(image_info,exception);
190
257
  status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
191
257
  if (status == MagickFalse)
192
0
    {
193
0
      image=DestroyImageList(image);
194
0
      return((Image *) NULL);
195
0
    }
196
257
  status=AcquireUniqueSymbolicLink(image_info->filename,input_filename);
197
257
  if (status == MagickFalse)
198
0
    {
199
0
      ThrowFileException(exception,FileOpenError,"UnableToCreateTemporaryFile",
200
0
        image_info->filename);
201
0
      image=DestroyImageList(image);
202
0
      return((Image *) NULL);
203
0
    }
204
  /*
205
    Set the page density.
206
  */
207
257
  delta.x=DefaultResolution;
208
257
  delta.y=DefaultResolution;
209
257
  if ((image->resolution.x == 0.0) || (image->resolution.y == 0.0))
210
257
    {
211
257
      flags=ParseGeometry(PSDensityGeometry,&geometry_info);
212
257
      if ((flags & RhoValue) != 0)
213
257
        image->resolution.x=geometry_info.rho;
214
257
      image->resolution.y=image->resolution.x;
215
257
      if ((flags & SigmaValue) != 0)
216
257
        image->resolution.y=geometry_info.sigma;
217
257
    }
218
257
  if (image_info->density != (char *) NULL)
219
0
    {
220
0
      flags=ParseGeometry(image_info->density,&geometry_info);
221
0
      if ((flags & RhoValue) != 0)
222
0
        image->resolution.x=geometry_info.rho;
223
0
      image->resolution.y=image->resolution.x;
224
0
      if ((flags & SigmaValue) != 0)
225
0
        image->resolution.y=geometry_info.sigma;
226
0
    }
227
257
  (void) ParseAbsoluteGeometry(PSPageGeometry,&page);
228
257
  if (image_info->page != (char *) NULL)
229
0
    (void) ParseAbsoluteGeometry(image_info->page,&page);
230
257
  resolution=image->resolution;
231
257
  page.width=(size_t) ((ssize_t) ceil((double) (page.width*resolution.x/
232
257
    delta.x)-0.5));
233
257
  page.height=(size_t) ((ssize_t) ceil((double) (page.height*resolution.y/
234
257
    delta.y)-0.5));
235
257
  fitPage=MagickFalse;
236
257
  option=GetImageOption(image_info,"xps:fit-page");
237
257
  if (option != (char *) NULL)
238
0
    {
239
0
      char
240
0
        *page_geometry;
241
242
0
      page_geometry=GetPageGeometry(option);
243
0
      flags=ParseMetaGeometry(page_geometry,&page.x,&page.y,&page.width,
244
0
        &page.height);
245
0
      if (flags == NoValue)
246
0
        {
247
0
          (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
248
0
            "InvalidGeometry","`%s'",option);
249
0
          page_geometry=DestroyString(page_geometry);
250
0
          image=DestroyImage(image);
251
0
          return((Image *) NULL);
252
0
        }
253
0
      page.width=(size_t) ((ssize_t) ceil((double) (page.width*
254
0
        image->resolution.x/delta.x)-0.5));
255
0
      page.height=(size_t) ((ssize_t) ceil((double) (page.height*
256
0
        image->resolution.y/delta.y) -0.5));
257
0
      page_geometry=DestroyString(page_geometry);
258
0
      fitPage=MagickTrue;
259
0
    }
260
  /*
261
    Render Postscript with the Ghostscript delegate.
262
  */
263
257
  delegate_info=GetDelegateInfo("xps:color",(char *) NULL,exception);
264
257
  if (delegate_info == (const DelegateInfo *) NULL)
265
0
    {
266
0
      image=DestroyImageList(image);
267
0
      return((Image *) NULL);
268
0
    }
269
257
  density=AcquireString("");
270
257
  options=AcquireString("");
271
257
  (void) FormatLocaleString(density,MagickPathExtent,"%gx%g",resolution.x,
272
257
    resolution.y);
273
257
  if (image_info->ping != MagickFalse)
274
0
    (void) FormatLocaleString(density,MagickPathExtent,"2.0x2.0");
275
257
  else
276
257
    (void) FormatLocaleString(options,MagickPathExtent,"-g%.20gx%.20g ",
277
257
      (double) page.width,(double) page.height);
278
257
  read_info=CloneImageInfo(image_info);
279
257
  *read_info->magick='\0';
280
257
  if (read_info->number_scenes != 0)
281
0
    {
282
0
      char
283
0
        pages[MagickPathExtent];
284
285
0
      (void) FormatLocaleString(pages,MagickPathExtent,"-dFirstPage=%.20g "
286
0
        "-dLastPage=%.20g ",(double) read_info->scene+1,(double)
287
0
        (read_info->scene+read_info->number_scenes));
288
0
      (void) ConcatenateMagickString(options,pages,MagickPathExtent);
289
0
      read_info->number_scenes=0;
290
0
      if (read_info->scenes != (char *) NULL)
291
0
        *read_info->scenes='\0';
292
0
    }
293
257
  if (*image_info->magick == 'E')
294
0
    {
295
0
      option=GetImageOption(image_info,"xps:use-cropbox");
296
0
      if ((option == (const char *) NULL) ||
297
0
          (IsStringTrue(option) != MagickFalse))
298
0
        (void) ConcatenateMagickString(options,"-dEPSCrop ",MagickPathExtent);
299
0
      if (fitPage != MagickFalse)
300
0
        (void) ConcatenateMagickString(options,"-dEPSFitPage ",
301
0
          MagickPathExtent);
302
0
    }
303
257
  (void) AcquireUniqueFilename(read_info->filename);
304
257
  (void) RelinquishUniqueFileResource(read_info->filename);
305
257
  (void) ConcatenateMagickString(read_info->filename,"%d",MagickPathExtent);
306
257
  (void) CopyMagickString(filename,read_info->filename,MagickPathExtent);
307
257
  (void) FormatLocaleString(command,MagickPathExtent,
308
257
    GetDelegateCommands(delegate_info),
309
257
    read_info->antialias != MagickFalse ? 4 : 1,
310
257
    read_info->antialias != MagickFalse ? 4 : 1,density,options,
311
257
    read_info->filename,input_filename);
312
257
  options=DestroyString(options);
313
257
  density=DestroyString(density);
314
257
  *message='\0';
315
257
  status=ExternalDelegateCommand(MagickFalse,read_info->verbose,command,
316
257
    (char *) NULL,exception) != 0 ? MagickTrue : MagickFalse;
317
257
  (void) RelinquishUniqueFileResource(input_filename);
318
257
  postscript_image=(Image *) NULL;
319
257
  if (status == MagickFalse)
320
0
    for (i=1; ; i++)
321
0
    {
322
0
      (void) InterpretImageFilename(image_info,image,filename,(int) i,
323
0
        read_info->filename,exception);
324
0
      if (IsGhostscriptRendered(read_info->filename) == MagickFalse)
325
0
        break;
326
0
      read_info->blob=NULL;
327
0
      read_info->length=0;
328
0
      next=ReadImage(read_info,exception);
329
0
      (void) RelinquishUniqueFileResource(read_info->filename);
330
0
      if (next == (Image *) NULL)
331
0
        break;
332
0
      AppendImageToList(&postscript_image,next);
333
0
    }
334
257
  (void) RelinquishUniqueFileResource(filename);
335
257
  read_info=DestroyImageInfo(read_info);
336
257
  if (postscript_image == (Image *) NULL)
337
257
    {
338
257
      if (*message != '\0')
339
0
        (void) ThrowMagickException(exception,GetMagickModule(),
340
0
          DelegateError,"PostscriptDelegateFailed","`%s'",message);
341
257
      image=DestroyImageList(image);
342
257
      return((Image *) NULL);
343
257
    }
344
0
  if (LocaleCompare(postscript_image->magick,"BMP") == 0)
345
0
    {
346
0
      Image
347
0
        *cmyk_image;
348
349
0
      cmyk_image=ConsolidateCMYKImages(postscript_image,exception);
350
0
      if (cmyk_image != (Image *) NULL)
351
0
        {
352
0
          postscript_image=DestroyImageList(postscript_image);
353
0
          postscript_image=cmyk_image;
354
0
        }
355
0
    }
356
0
  if (image_info->number_scenes != 0)
357
0
    {
358
0
      Image
359
0
        *clone_image;
360
361
      /*
362
        Add place holder images to meet the subimage specification requirement.
363
      */
364
0
      for (i=0; i < (ssize_t) image_info->scene; i++)
365
0
      {
366
0
        clone_image=CloneImage(postscript_image,1,1,MagickTrue,exception);
367
0
        if (clone_image != (Image *) NULL)
368
0
          PrependImageToList(&postscript_image,clone_image);
369
0
      }
370
0
    }
371
0
  do
372
0
  {
373
0
    (void) CopyMagickString(postscript_image->filename,filename,
374
0
      MagickPathExtent);
375
0
    (void) CopyMagickString(postscript_image->magick,image->magick,
376
0
      MagickPathExtent);
377
0
    postscript_image->page=page;
378
0
    if (image_info->ping != MagickFalse)
379
0
      {
380
0
        postscript_image->magick_columns=page.width;
381
0
        postscript_image->magick_rows=page.height;
382
0
        postscript_image->columns=page.width;
383
0
        postscript_image->rows=page.height;
384
0
      }
385
0
    (void) CloneImageProfiles(postscript_image,image);
386
0
    (void) CloneImageProperties(postscript_image,image);
387
0
    next=SyncNextImageInList(postscript_image);
388
0
    if (next != (Image *) NULL)
389
0
      postscript_image=next;
390
0
  } while (next != (Image *) NULL);
391
0
  image=DestroyImageList(image);
392
0
  scene=0;
393
0
  for (next=GetFirstImageInList(postscript_image); next != (Image *) NULL; )
394
0
  {
395
0
    next->scene=scene++;
396
0
    next=GetNextImageInList(next);
397
0
  }
398
0
  return(GetFirstImageInList(postscript_image));
399
257
}
400

401
/*
402
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
403
%                                                                             %
404
%                                                                             %
405
%                                                                             %
406
%   R e g i s t e r X P S I m a g e                                           %
407
%                                                                             %
408
%                                                                             %
409
%                                                                             %
410
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
411
%
412
%  RegisterXPSImage() adds properties for the PS image format to
413
%  the list of supported formats.  The properties include the image format
414
%  tag, a method to read and/or write the format, whether the format
415
%  supports the saving of more than one frame to the same file or blob,
416
%  whether the format supports native in-memory I/O, and a brief
417
%  description of the format.
418
%
419
%  The format of the RegisterXPSImage method is:
420
%
421
%      size_t RegisterXPSImage(void)
422
%
423
*/
424
ModuleExport size_t RegisterXPSImage(void)
425
8
{
426
8
  MagickInfo
427
8
    *entry;
428
429
8
  entry=AcquireMagickInfo("XPS","XPS","Microsoft XML Paper Specification");
430
8
  entry->decoder=(DecodeImageHandler *) ReadXPSImage;
431
8
  entry->flags|=CoderDecoderSeekableStreamFlag;
432
8
  entry->flags^=CoderAdjoinFlag;
433
8
  entry->flags^=CoderBlobSupportFlag;
434
8
  entry->mime_type=ConstantString("application/oxps");
435
8
  (void) RegisterMagickInfo(entry);
436
8
  return(MagickImageCoderSignature);
437
8
}
438

439
/*
440
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
441
%                                                                             %
442
%                                                                             %
443
%                                                                             %
444
%   U n r e g i s t e r X P S I m a g e                                       %
445
%                                                                             %
446
%                                                                             %
447
%                                                                             %
448
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
449
%
450
%  UnregisterXPSImage() removes format registrations made by the
451
%  XPS module from the list of supported formats.
452
%
453
%  The format of the UnregisterXPSImage method is:
454
%
455
%      UnregisterXPSImage(void)
456
%
457
*/
458
ModuleExport void UnregisterXPSImage(void)
459
0
{
460
0
  (void) UnregisterMagickInfo("XPS");
461
0
}