1/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3%                                                                             %
4%                                                                             %
5%                                                                             %
6%                            DDDD   PPPP   SSSSS                              %
7%                            D   D  P   P  SS                                 %
8%                            D   D  PPPP    SSS                               %
9%                            D   D  P         SS                              %
10%                            DDDD   P      SSSSS                              %
11%                                                                             %
12%                                                                             %
13%            Read Postscript Using the Display Postscript System.             %
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/blob.h"
44#include "MagickCore/blob-private.h"
45#include "MagickCore/client.h"
46#include "MagickCore/colormap.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/monitor.h"
55#include "MagickCore/monitor-private.h"
56#include "MagickCore/pixel-accessor.h"
57#include "MagickCore/quantum-private.h"
58#include "MagickCore/static.h"
59#include "MagickCore/string_.h"
60#include "MagickCore/module.h"
61#include "MagickCore/utility.h"
62#include "MagickCore/xwindow-private.h"
63#if defined(MAGICKCORE_DPS_DELEGATE)
64#include <DPS/dpsXclient.h>
65#include <DPS/dpsXpreview.h>
66#endif
67
68#if defined(MAGICKCORE_DPS_DELEGATE)
69/*
70%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
71%                                                                             %
72%                                                                             %
73%                                                                             %
74%   R e a d D P S I m a g e                                                   %
75%                                                                             %
76%                                                                             %
77%                                                                             %
78%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
79%
80%  ReadDPSImage() reads a Adobe Postscript image file and returns it.  It
81%  allocates the memory necessary for the new Image structure and returns a
82%  pointer to the new image.
83%
84%  The format of the ReadDPSImage method is:
85%
86%      Image *ReadDPSImage(const ImageInfo *image_info,ExceptionInfo *exception)
87%
88%  A description of each parameter follows:
89%
90%    o image_info: the image info.
91%
92%    o exception: return any errors or warnings in this structure.
93%
94*/
95static Image *ReadDPSImage(const ImageInfo *image_info,ExceptionInfo *exception)
96{
97  const char
98    *client_name;
99
100  Display
101    *display;
102
103  float
104    pixels_per_point;
105
106  Image
107    *image;
108
109  int
110    sans,
111    status;
112
113  Pixmap
114    pixmap;
115
116  register ssize_t
117    i;
118
119  register Quantum
120    *q;
121
122  register size_t
123    pixel;
124
125  Screen
126    *screen;
127
128  ssize_t
129    x,
130    y;
131
132  XColor
133    *colors;
134
135  XImage
136    *dps_image;
137
138  XRectangle
139    page,
140    bits_per_pixel;
141
142  XResourceInfo
143    resource_info;
144
145  XrmDatabase
146    resource_database;
147
148  XStandardColormap
149    *map_info;
150
151  XVisualInfo
152    *visual_info;
153
154  /*
155    Open X server connection.
156  */
157  assert(image_info != (const ImageInfo *) NULL);
158  assert(image_info->signature == MagickCoreSignature);
159  if (image_info->debug != MagickFalse)
160    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
161      image_info->filename);
162  assert(exception != (ExceptionInfo *) NULL);
163  assert(exception->signature == MagickCoreSignature);
164  display=XOpenDisplay(image_info->server_name);
165  if (display == (Display *) NULL)
166    return((Image *) NULL);
167  /*
168    Set our forgiving exception handler.
169  */
170  (void) XSetErrorHandler(XError);
171  /*
172    Open image file.
173  */
174  image=AcquireImage(image_info,exception);
175  status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
176  if (status == MagickFalse)
177    return((Image *) NULL);
178  /*
179    Get user defaults from X resource database.
180  */
181  client_name=GetClientName();
182  resource_database=XGetResourceDatabase(display,client_name);
183  XGetResourceInfo(image_info,resource_database,client_name,&resource_info);
184  /*
185    Allocate standard colormap.
186  */
187  map_info=XAllocStandardColormap();
188  visual_info=(XVisualInfo *) NULL;
189  if (map_info == (XStandardColormap *) NULL)
190    ThrowReaderException(ResourceLimitError,"UnableToCreateStandardColormap")
191  else
192    {
193      /*
194        Initialize visual info.
195      */
196      (void) CloneString(&resource_info.visual_type,"default");
197      visual_info=XBestVisualInfo(display,map_info,&resource_info);
198      map_info->colormap=(Colormap) NULL;
199    }
200  if ((map_info == (XStandardColormap *) NULL) ||
201      (visual_info == (XVisualInfo *) NULL))
202    {
203      image=DestroyImage(image);
204      XFreeResources(display,visual_info,map_info,(XPixelInfo *) NULL,
205        (XFontStruct *) NULL,&resource_info,(XWindowInfo *) NULL);
206      return((Image *) NULL);
207    }
208  /*
209    Create a pixmap the appropriate size for the image.
210  */
211  screen=ScreenOfDisplay(display,visual_info->screen);
212  pixels_per_point=XDPSPixelsPerPoint(screen);
213  if ((image->resolution.x != 0.0) && (image->resolution.y != 0.0))
214    pixels_per_point=MagickMin(image->resolution.x,image->resolution.y)/
215      DefaultResolution;
216  status=XDPSCreatePixmapForEPSF((DPSContext) NULL,screen,
217    GetBlobFileHandle(image),visual_info->depth,pixels_per_point,&pixmap,
218    &bits_per_pixel,&page);
219  if ((status == dps_status_failure) || (status == dps_status_no_extension))
220    {
221      image=DestroyImage(image);
222      XFreeResources(display,visual_info,map_info,(XPixelInfo *) NULL,
223        (XFontStruct *) NULL,&resource_info,(XWindowInfo *) NULL);
224      return((Image *) NULL);
225    }
226  /*
227    Rasterize the file into the pixmap.
228  */
229  status=XDPSImageFileIntoDrawable((DPSContext) NULL,screen,pixmap,
230    GetBlobFileHandle(image),(int) bits_per_pixel.height,visual_info->depth,
231    &page,-page.x,-page.y,pixels_per_point,MagickTrue,MagickFalse,MagickTrue,
232    &sans);
233  if (status != dps_status_success)
234    {
235      image=DestroyImage(image);
236      XFreeResources(display,visual_info,map_info,(XPixelInfo *) NULL,
237        (XFontStruct *) NULL,&resource_info,(XWindowInfo *) NULL);
238      return((Image *) NULL);
239    }
240  /*
241    Initialize DPS X image.
242  */
243  dps_image=XGetImage(display,pixmap,0,0,bits_per_pixel.width,
244    bits_per_pixel.height,AllPlanes,ZPixmap);
245  (void) XFreePixmap(display,pixmap);
246  if (dps_image == (XImage *) NULL)
247    {
248      image=DestroyImage(image);
249      XFreeResources(display,visual_info,map_info,(XPixelInfo *) NULL,
250        (XFontStruct *) NULL,&resource_info,(XWindowInfo *) NULL);
251      return((Image *) NULL);
252    }
253  /*
254    Get the colormap colors.
255  */
256  colors=(XColor *) AcquireQuantumMemory(visual_info->colormap_size,
257    sizeof(*colors));
258  if (colors == (XColor *) NULL)
259    {
260      image=DestroyImage(image);
261      XDestroyImage(dps_image);
262      XFreeResources(display,visual_info,map_info,(XPixelInfo *) NULL,
263        (XFontStruct *) NULL,&resource_info,(XWindowInfo *) NULL);
264      return((Image *) NULL);
265    }
266  if ((visual_info->klass != DirectColor) && (visual_info->klass != TrueColor))
267    for (i=0; i < visual_info->colormap_size; i++)
268    {
269      colors[i].pixel=(size_t) i;
270      colors[i].pad=0;
271    }
272  else
273    {
274      size_t
275        blue,
276        blue_bit,
277        green,
278        green_bit,
279        red,
280        red_bit;
281
282      /*
283        DirectColor or TrueColor visual.
284      */
285      red=0;
286      green=0;
287      blue=0;
288      red_bit=visual_info->red_mask & (~(visual_info->red_mask)+1);
289      green_bit=visual_info->green_mask & (~(visual_info->green_mask)+1);
290      blue_bit=visual_info->blue_mask & (~(visual_info->blue_mask)+1);
291      for (i=0; i < visual_info->colormap_size; i++)
292      {
293        colors[i].pixel=red | green | blue;
294        colors[i].pad=0;
295        red+=red_bit;
296        if (red > visual_info->red_mask)
297          red=0;
298        green+=green_bit;
299        if (green > visual_info->green_mask)
300          green=0;
301        blue+=blue_bit;
302        if (blue > visual_info->blue_mask)
303          blue=0;
304      }
305    }
306  (void) XQueryColors(display,XDefaultColormap(display,visual_info->screen),
307    colors,visual_info->colormap_size);
308  /*
309    Convert X image to MIFF format.
310  */
311  if ((visual_info->klass != TrueColor) && (visual_info->klass != DirectColor))
312    image->storage_class=PseudoClass;
313  image->columns=(size_t) dps_image->width;
314  image->rows=(size_t) dps_image->height;
315  if (image_info->ping != MagickFalse)
316    {
317      (void) CloseBlob(image);
318      return(GetFirstImageInList(image));
319    }
320  status=SetImageExtent(image,image->columns,image->rows,exception);
321  if (status == MagickFalse)
322    return(DestroyImageList(image));
323  switch (image->storage_class)
324  {
325    case DirectClass:
326    default:
327    {
328      register size_t
329        color,
330        index;
331
332      size_t
333        blue_mask,
334        blue_shift,
335        green_mask,
336        green_shift,
337        red_mask,
338        red_shift;
339
340      /*
341        Determine shift and mask for red, green, and blue.
342      */
343      red_mask=visual_info->red_mask;
344      red_shift=0;
345      while ((red_mask != 0) && ((red_mask & 0x01) == 0))
346      {
347        red_mask>>=1;
348        red_shift++;
349      }
350      green_mask=visual_info->green_mask;
351      green_shift=0;
352      while ((green_mask != 0) && ((green_mask & 0x01) == 0))
353      {
354        green_mask>>=1;
355        green_shift++;
356      }
357      blue_mask=visual_info->blue_mask;
358      blue_shift=0;
359      while ((blue_mask != 0) && ((blue_mask & 0x01) == 0))
360      {
361        blue_mask>>=1;
362        blue_shift++;
363      }
364      /*
365        Convert X image to DirectClass packets.
366      */
367      if ((visual_info->colormap_size > 0) &&
368          (visual_info->klass == DirectColor))
369        for (y=0; y < (ssize_t) image->rows; y++)
370        {
371          q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
372          if (q == (Quantum *) NULL)
373            break;
374          for (x=0; x < (ssize_t) image->columns; x++)
375          {
376            pixel=XGetPixel(dps_image,x,y);
377            index=(pixel >> red_shift) & red_mask;
378            SetPixelRed(image,ScaleShortToQuantum(colors[index].red),q);
379            index=(pixel >> green_shift) & green_mask;
380            SetPixelGreen(image,ScaleShortToQuantum(colors[index].green),q);
381            index=(pixel >> blue_shift) & blue_mask;
382            SetPixelBlue(image,ScaleShortToQuantum(colors[index].blue),q);
383            q+=GetPixelChannels(image);
384          }
385          if (SyncAuthenticPixels(image,exception) == MagickFalse)
386            break;
387          if (SetImageProgress(image,LoadImageTag,y,image->rows) == MagickFalse)
388            break;
389        }
390      else
391        for (y=0; y < (ssize_t) image->rows; y++)
392        {
393          q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
394          if (q == (Quantum *) NULL)
395            break;
396          for (x=0; x < (ssize_t) image->columns; x++)
397          {
398            pixel=XGetPixel(dps_image,x,y);
399            color=(pixel >> red_shift) & red_mask;
400            color=(color*65535L)/red_mask;
401            SetPixelRed(image,ScaleShortToQuantum((unsigned short) color),q);
402            color=(pixel >> green_shift) & green_mask;
403            color=(color*65535L)/green_mask;
404            SetPixelGreen(image,ScaleShortToQuantum((unsigned short) color),q);
405            color=(pixel >> blue_shift) & blue_mask;
406            color=(color*65535L)/blue_mask;
407            SetPixelBlue(image,ScaleShortToQuantum((unsigned short) color),q);
408            q+=GetPixelChannels(image);
409          }
410          if (SyncAuthenticPixels(image,exception) == MagickFalse)
411            break;
412          if (SetImageProgress(image,LoadImageTag,y,image->rows) == MagickFalse)
413            break;
414        }
415      break;
416    }
417    case PseudoClass:
418    {
419      /*
420        Create colormap.
421      */
422      if (AcquireImageColormap(image,(size_t) visual_info->colormap_size,exception) == MagickFalse)
423        {
424          image=DestroyImage(image);
425          colors=(XColor *) RelinquishMagickMemory(colors);
426          XDestroyImage(dps_image);
427          XFreeResources(display,visual_info,map_info,(XPixelInfo *) NULL,
428            (XFontStruct *) NULL,&resource_info,(XWindowInfo *) NULL);
429          return((Image *) NULL);
430        }
431      for (i=0; i < (ssize_t) image->colors; i++)
432      {
433        image->colormap[colors[i].pixel].red=ScaleShortToQuantum(colors[i].red);
434        image->colormap[colors[i].pixel].green=
435          ScaleShortToQuantum(colors[i].green);
436        image->colormap[colors[i].pixel].blue=
437          ScaleShortToQuantum(colors[i].blue);
438      }
439      /*
440        Convert X image to PseudoClass packets.
441      */
442      for (y=0; y < (ssize_t) image->rows; y++)
443      {
444        q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
445        if (q == (Quantum *) NULL)
446          break;
447        for (x=0; x < (ssize_t) image->columns; x++)
448        {
449          SetPixelIndex(image,(unsigned short) XGetPixel(dps_image,x,y),q);
450          q+=GetPixelChannels(image);
451        }
452        if (SyncAuthenticPixels(image,exception) == MagickFalse)
453          break;
454        if (SetImageProgress(image,LoadImageTag,y,image->rows) == MagickFalse)
455          break;
456      }
457      break;
458    }
459  }
460  colors=(XColor *) RelinquishMagickMemory(colors);
461  XDestroyImage(dps_image);
462  if (image->storage_class == PseudoClass)
463    (void) SyncImage(image,exception);
464  /*
465    Rasterize matte image.
466  */
467  status=XDPSCreatePixmapForEPSF((DPSContext) NULL,screen,
468    GetBlobFileHandle(image),1,pixels_per_point,&pixmap,&bits_per_pixel,&page);
469  if ((status != dps_status_failure) && (status != dps_status_no_extension))
470    {
471      status=XDPSImageFileIntoDrawable((DPSContext) NULL,screen,pixmap,
472        GetBlobFileHandle(image),(int) bits_per_pixel.height,1,&page,-page.x,
473        -page.y,pixels_per_point,MagickTrue,MagickTrue,MagickTrue,&sans);
474      if (status == dps_status_success)
475        {
476          XImage
477            *matte_image;
478
479          /*
480            Initialize image matte.
481          */
482          matte_image=XGetImage(display,pixmap,0,0,bits_per_pixel.width,
483            bits_per_pixel.height,AllPlanes,ZPixmap);
484          (void) XFreePixmap(display,pixmap);
485          if (matte_image != (XImage *) NULL)
486            {
487              image->storage_class=DirectClass;
488              image->alpha_trait=BlendPixelTrait;
489              for (y=0; y < (ssize_t) image->rows; y++)
490              {
491                q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
492                if (q == (Quantum *) NULL)
493                  break;
494                for (x=0; x < (ssize_t) image->columns; x++)
495                {
496                  SetPixelAlpha(image,OpaqueAlpha,q);
497                  if (XGetPixel(matte_image,x,y) == 0)
498                    SetPixelAlpha(image,TransparentAlpha,q);
499                  q+=GetPixelChannels(image);
500                }
501                if (SyncAuthenticPixels(image,exception) == MagickFalse)
502                  break;
503              }
504              XDestroyImage(matte_image);
505            }
506        }
507    }
508  /*
509    Relinquish resources.
510  */
511  XFreeResources(display,visual_info,map_info,(XPixelInfo *) NULL,
512    (XFontStruct *) NULL,&resource_info,(XWindowInfo *) NULL);
513  (void) CloseBlob(image);
514  return(GetFirstImageInList(image));
515}
516#endif
517
518/*
519%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
520%                                                                             %
521%                                                                             %
522%                                                                             %
523%   R e g i s t e r D P S I m a g e                                           %
524%                                                                             %
525%                                                                             %
526%                                                                             %
527%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
528%
529%  RegisterDPSImage() adds attributes for the Display Postscript image
530%  format to the list of supported formats.  The attributes include the image
531%  format tag, a method to read and/or write the format, whether the format
532%  supports the saving of more than one frame to the same file or blob,
533%  whether the format supports native in-memory I/O, and a brief
534%  description of the format.
535%
536%  The format of the RegisterDPSImage method is:
537%
538%      size_t RegisterDPSImage(void)
539%
540*/
541ModuleExport size_t RegisterDPSImage(void)
542{
543  MagickInfo
544    *entry;
545
546  entry=AcquireMagickInfo("DPS","DPS","Display Postscript Interpreter");
547#if defined(MAGICKCORE_DPS_DELEGATE)
548  entry->decoder=(DecodeImageHandler *) ReadDPSImage;
549#endif
550  entry->flags^=CoderBlobSupportFlag;
551  (void) RegisterMagickInfo(entry);
552  return(MagickImageCoderSignature);
553}
554
555/*
556%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
557%                                                                             %
558%                                                                             %
559%                                                                             %
560%   U n r e g i s t e r D P S I m a g e                                       %
561%                                                                             %
562%                                                                             %
563%                                                                             %
564%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
565%
566%  UnregisterDPSImage() removes format registrations made by the
567%  DPS module from the list of supported formats.
568%
569%  The format of the UnregisterDPSImage method is:
570%
571%      UnregisterDPSImage(void)
572%
573*/
574ModuleExport void UnregisterDPSImage(void)
575{
576  (void) UnregisterMagickInfo("DPS");
577}
578