xps.c revision 9950d57e1124b73f684fb5946e206994cefda628
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%                                John Cristy                                  %
17%                               January 2008                                  %
18%                                                                             %
19%                                                                             %
20%  Copyright 1999-2011 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/property.h"
44#include "MagickCore/blob.h"
45#include "MagickCore/blob-private.h"
46#include "MagickCore/color.h"
47#include "MagickCore/color-private.h"
48#include "MagickCore/colorspace.h"
49#include "MagickCore/constitute.h"
50#include "MagickCore/delegate.h"
51#include "MagickCore/draw.h"
52#include "MagickCore/exception.h"
53#include "MagickCore/exception-private.h"
54#include "MagickCore/geometry.h"
55#include "MagickCore/image.h"
56#include "MagickCore/image-private.h"
57#include "MagickCore/list.h"
58#include "MagickCore/magick.h"
59#include "MagickCore/memory_.h"
60#include "MagickCore/monitor.h"
61#include "MagickCore/monitor-private.h"
62#include "MagickCore/profile.h"
63#include "MagickCore/resource_.h"
64#include "MagickCore/quantum-private.h"
65#include "MagickCore/static.h"
66#include "MagickCore/string_.h"
67#include "MagickCore/module.h"
68#include "MagickCore/token.h"
69#include "MagickCore/transform.h"
70#include "MagickCore/utility.h"
71
72/*
73%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
74%                                                                             %
75%                                                                             %
76%                                                                             %
77%   R e a d X P S I m a g e                                                   %
78%                                                                             %
79%                                                                             %
80%                                                                             %
81%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
82%
83%  ReadXPSImage() reads a Printer Control Language image file and returns it.
84%  It allocates the memory necessary for the new Image structure and returns a
85%  pointer to the new image.
86%
87%  The format of the ReadXPSImage method is:
88%
89%      Image *ReadXPSImage(const ImageInfo *image_info,ExceptionInfo *exception)
90%
91%  A description of each parameter follows:
92%
93%    o image_info: the image info.
94%
95%    o exception: return any errors or warnings in this structure.
96%
97*/
98static Image *ReadXPSImage(const ImageInfo *image_info,ExceptionInfo *exception)
99{
100#define CropBox  "CropBox"
101#define DeviceCMYK  "DeviceCMYK"
102#define MediaBox  "MediaBox"
103#define RenderXPSText  "  Rendering XPS...  "
104
105  char
106    command[MaxTextExtent],
107    density[MaxTextExtent],
108    filename[MaxTextExtent],
109    geometry[MaxTextExtent],
110    options[MaxTextExtent],
111    input_filename[MaxTextExtent];
112
113  const DelegateInfo
114    *delegate_info;
115
116  Image
117    *image,
118    *next_image;
119
120  ImageInfo
121    *read_info;
122
123  MagickBooleanType
124    cmyk,
125    status;
126
127  PointInfo
128    delta;
129
130  RectangleInfo
131    bounding_box,
132    page;
133
134  register char
135    *p;
136
137  register ssize_t
138    c;
139
140  SegmentInfo
141    bounds;
142
143  size_t
144    height,
145    width;
146
147  ssize_t
148    count;
149
150  assert(image_info != (const ImageInfo *) NULL);
151  assert(image_info->signature == MagickSignature);
152  if (image_info->debug != MagickFalse)
153    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
154      image_info->filename);
155  assert(exception != (ExceptionInfo *) NULL);
156  assert(exception->signature == MagickSignature);
157  /*
158    Open image file.
159  */
160  image=AcquireImage(image_info,exception);
161  status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
162  if (status == MagickFalse)
163    {
164      image=DestroyImageList(image);
165      return((Image *) NULL);
166    }
167  status=AcquireUniqueSymbolicLink(image_info->filename,input_filename);
168  if (status == MagickFalse)
169    {
170      ThrowFileException(exception,FileOpenError,"UnableToCreateTemporaryFile",
171        image_info->filename);
172      image=DestroyImageList(image);
173      return((Image *) NULL);
174    }
175  /*
176    Set the page density.
177  */
178  delta.x=DefaultResolution;
179  delta.y=DefaultResolution;
180  if ((image->x_resolution == 0.0) || (image->y_resolution == 0.0))
181    {
182      GeometryInfo
183        geometry_info;
184
185      MagickStatusType
186        flags;
187
188      flags=ParseGeometry(PSDensityGeometry,&geometry_info);
189      image->x_resolution=geometry_info.rho;
190      image->y_resolution=geometry_info.sigma;
191      if ((flags & SigmaValue) == 0)
192        image->y_resolution=image->x_resolution;
193    }
194  (void) FormatLocaleString(density,MaxTextExtent,"%gx%g",
195    image->x_resolution,image->y_resolution);
196  /*
197    Determine page geometry from the XPS media box.
198  */
199  cmyk=image->colorspace == CMYKColorspace ? MagickTrue : MagickFalse;
200  count=0;
201  (void) ResetMagickMemory(&bounding_box,0,sizeof(bounding_box));
202  (void) ResetMagickMemory(&bounds,0,sizeof(bounds));
203  (void) ResetMagickMemory(&page,0,sizeof(page));
204  (void) ResetMagickMemory(command,0,sizeof(command));
205  p=command;
206  for (c=ReadBlobByte(image); c != EOF; c=ReadBlobByte(image))
207  {
208    if (image_info->page != (char *) NULL)
209      continue;
210    /*
211      Note XPS elements.
212    */
213    *p++=(char) c;
214    if ((c != (int) '/') && (c != '\n') &&
215        ((size_t) (p-command) < (MaxTextExtent-1)))
216      continue;
217    *p='\0';
218    p=command;
219    /*
220      Is this a CMYK document?
221    */
222    if (LocaleNCompare(DeviceCMYK,command,strlen(DeviceCMYK)) == 0)
223      cmyk=MagickTrue;
224    if (LocaleNCompare(CropBox,command,strlen(CropBox)) == 0)
225      {
226        /*
227          Note region defined by crop box.
228        */
229        count=(ssize_t) sscanf(command,"CropBox [%lf %lf %lf %lf",
230          &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
231        if (count != 4)
232          count=(ssize_t) sscanf(command,"CropBox[%lf %lf %lf %lf",
233            &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
234      }
235    if (LocaleNCompare(MediaBox,command,strlen(MediaBox)) == 0)
236      {
237        /*
238          Note region defined by media box.
239        */
240        count=(ssize_t) sscanf(command,"MediaBox [%lf %lf %lf %lf",
241          &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
242        if (count != 4)
243          count=(ssize_t) sscanf(command,"MediaBox[%lf %lf %lf %lf",
244            &bounds.x1,&bounds.y1,&bounds.x2,&bounds.y2);
245      }
246    if (count != 4)
247      continue;
248    /*
249      Set XPS render geometry.
250    */
251    width=(size_t) floor(bounds.x2-bounds.x1+0.5);
252    height=(size_t) floor(bounds.y2-bounds.y1+0.5);
253    if (width > page.width)
254      page.width=width;
255    if (height > page.height)
256      page.height=height;
257  }
258  (void) CloseBlob(image);
259  /*
260    Render XPS with the GhostXPS delegate.
261  */
262  if ((page.width == 0) || (page.height == 0))
263    (void) ParseAbsoluteGeometry(PSPageGeometry,&page);
264  if (image_info->page != (char *) NULL)
265    (void) ParseAbsoluteGeometry(image_info->page,&page);
266  (void) FormatLocaleString(geometry,MaxTextExtent,"%.20gx%.20g",(double)
267    page.width,(double) page.height);
268  if (image_info->monochrome != MagickFalse)
269    delegate_info=GetDelegateInfo("xps:mono",(char *) NULL,exception);
270  else
271     if (cmyk != MagickFalse)
272       delegate_info=GetDelegateInfo("xps:cmyk",(char *) NULL,exception);
273     else
274       delegate_info=GetDelegateInfo("xps:color",(char *) NULL,exception);
275  if (delegate_info == (const DelegateInfo *) NULL)
276    return((Image *) NULL);
277  *options='\0';
278  if ((page.width == 0) || (page.height == 0))
279    (void) ParseAbsoluteGeometry(PSPageGeometry,&page);
280  if (image_info->page != (char *) NULL)
281    (void) ParseAbsoluteGeometry(image_info->page,&page);
282  page.width=(size_t) floor(page.width*image->y_resolution/delta.x+0.5);
283  page.height=(size_t) floor(page.height*image->y_resolution/delta.y+
284    0.5);
285  (void) FormatLocaleString(options,MaxTextExtent,"-g%.20gx%.20g ",(double)
286    page.width,(double) page.height);
287  image=DestroyImage(image);
288  read_info=CloneImageInfo(image_info);
289  *read_info->magick='\0';
290  if (read_info->number_scenes != 0)
291    {
292      if (read_info->number_scenes != 1)
293        (void) FormatLocaleString(options,MaxTextExtent,"-dLastPage=%.20g",
294          (double) (read_info->scene+read_info->number_scenes));
295      else
296        (void) FormatLocaleString(options,MaxTextExtent,
297          "-dFirstPage=%.20g -dLastPage=%.20g",(double) read_info->scene+1,
298          (double) (read_info->scene+read_info->number_scenes));
299      read_info->number_scenes=0;
300      if (read_info->scenes != (char *) NULL)
301        *read_info->scenes='\0';
302    }
303  if (read_info->authenticate != (char *) NULL)
304    (void) FormatLocaleString(options+strlen(options),MaxTextExtent,
305      " -sXPSPassword=%s",read_info->authenticate);
306  (void) CopyMagickString(filename,read_info->filename,MaxTextExtent);
307  (void) AcquireUniqueFilename(read_info->filename);
308  (void) FormatLocaleString(command,MaxTextExtent,
309    GetDelegateCommands(delegate_info),
310    read_info->antialias != MagickFalse ? 4 : 1,
311    read_info->antialias != MagickFalse ? 4 : 1,density,options,
312    read_info->filename,input_filename);
313  status=SystemCommand(MagickFalse,read_info->verbose,command,exception) != 0 ?
314    MagickTrue : MagickFalse;
315  image=ReadImage(read_info,exception);
316  (void) RelinquishUniqueFileResource(read_info->filename);
317  (void) RelinquishUniqueFileResource(input_filename);
318  read_info=DestroyImageInfo(read_info);
319  if (image == (Image *) NULL)
320    ThrowReaderException(DelegateError,"XPSDelegateFailed");
321  if (LocaleCompare(image->magick,"BMP") == 0)
322    {
323      Image
324        *cmyk_image;
325
326      cmyk_image=ConsolidateCMYKImages(image,&image->exception);
327      if (cmyk_image != (Image *) NULL)
328        {
329          image=DestroyImageList(image);
330          image=cmyk_image;
331        }
332    }
333  do
334  {
335    (void) CopyMagickString(image->filename,filename,MaxTextExtent);
336    image->page=page;
337    next_image=SyncNextImageInList(image);
338    if (next_image != (Image *) NULL)
339      image=next_image;
340  } while (next_image != (Image *) NULL);
341  return(GetFirstImageInList(image));
342}
343
344/*
345%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
346%                                                                             %
347%                                                                             %
348%                                                                             %
349%   R e g i s t e r X P S I m a g e                                           %
350%                                                                             %
351%                                                                             %
352%                                                                             %
353%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
354%
355%  RegisterXPSImage() adds attributes for the Microsoft XML Paper Specification
356%  format to the list of supported formats.  The attributes include the image
357%  format tag, a method to read and/or write the format, whether the format
358%  supports the saving of more than one frame to the same file or blob,
359%  whether the format supports native in-memory I/O, and a brief
360%  description of the format.
361%
362%  The format of the RegisterXPSImage method is:
363%
364%      size_t RegisterXPSImage(void)
365%
366*/
367ModuleExport size_t RegisterXPSImage(void)
368{
369  MagickInfo
370    *entry;
371
372  entry=SetMagickInfo("XPS");
373  entry->decoder=(DecodeImageHandler *) ReadXPSImage;
374  entry->adjoin=MagickFalse;
375  entry->blob_support=MagickFalse;
376  entry->seekable_stream=MagickTrue;
377  entry->thread_support=EncoderThreadSupport;
378  entry->description=ConstantString("Microsoft XML Paper Specification");
379  entry->module=ConstantString("XPS");
380  (void) RegisterMagickInfo(entry);
381  return(MagickImageCoderSignature);
382}
383
384/*
385%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
386%                                                                             %
387%                                                                             %
388%                                                                             %
389%   U n r e g i s t e r X P S I m a g e                                       %
390%                                                                             %
391%                                                                             %
392%                                                                             %
393%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
394%
395%  UnregisterXPSImage() removes format registrations made by the XPS module
396%  from the list of supported formats.
397%
398%  The format of the UnregisterXPSImage method is:
399%
400%      UnregisterXPSImage(void)
401%
402*/
403ModuleExport void UnregisterXPSImage(void)
404{
405  (void) UnregisterMagickInfo("XPS");
406}
407