1/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3%                                                                             %
4%                                                                             %
5%                                                                             %
6%                            U   U  IIIII  L                                  %
7%                            U   U    I    L                                  %
8%                            U   U    I    L                                  %
9%                            U   U    I    L                                  %
10%                             UUU   IIIII  LLLLL                              %
11%                                                                             %
12%                                                                             %
13%                          Write X-Motif UIL Table.                           %
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/attribute.h"
44#include "MagickCore/blob.h"
45#include "MagickCore/blob-private.h"
46#include "MagickCore/cache.h"
47#include "MagickCore/color.h"
48#include "MagickCore/color-private.h"
49#include "MagickCore/colorspace.h"
50#include "MagickCore/colorspace-private.h"
51#include "MagickCore/exception.h"
52#include "MagickCore/exception-private.h"
53#include "MagickCore/image-private.h"
54#include "MagickCore/magick.h"
55#include "MagickCore/memory_.h"
56#include "MagickCore/monitor.h"
57#include "MagickCore/monitor-private.h"
58#include "MagickCore/pixel-accessor.h"
59#include "MagickCore/quantum-private.h"
60#include "MagickCore/static.h"
61#include "MagickCore/string_.h"
62#include "MagickCore/module.h"
63#include "MagickCore/utility.h"
64
65/*
66  Forward declarations.
67*/
68static MagickBooleanType
69  WriteUILImage(const ImageInfo *,Image *,ExceptionInfo *);
70
71/*
72%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
73%                                                                             %
74%                                                                             %
75%                                                                             %
76%   R e g i s t e r U I L I m a g e                                           %
77%                                                                             %
78%                                                                             %
79%                                                                             %
80%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
81%
82%  RegisterUILImage() adds attributes for the UIL image format to
83%  the list of supported formats.  The attributes include the image format
84%  tag, a method to read and/or write the format, whether the format
85%  supports the saving of more than one frame to the same file or blob,
86%  whether the format supports native in-memory I/O, and a brief
87%  description of the format.
88%
89%  The format of the RegisterUILImage method is:
90%
91%      size_t RegisterUILImage(void)
92%
93*/
94ModuleExport size_t RegisterUILImage(void)
95{
96  MagickInfo
97    *entry;
98
99  entry=AcquireMagickInfo("UIL","UIL","X-Motif UIL table");
100  entry->encoder=(EncodeImageHandler *) WriteUILImage;
101  entry->flags^=CoderAdjoinFlag;
102  (void) RegisterMagickInfo(entry);
103  return(MagickImageCoderSignature);
104}
105
106/*
107%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
108%                                                                             %
109%                                                                             %
110%                                                                             %
111%   U n r e g i s t e r U I L I m a g e                                       %
112%                                                                             %
113%                                                                             %
114%                                                                             %
115%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
116%
117%  UnregisterUILImage() removes format registrations made by the
118%  UIL module from the list of supported formats.
119%
120%  The format of the UnregisterUILImage method is:
121%
122%      UnregisterUILImage(void)
123%
124*/
125ModuleExport void UnregisterUILImage(void)
126{
127  (void) UnregisterMagickInfo("UIL");
128}
129
130/*
131%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
132%                                                                             %
133%                                                                             %
134%                                                                             %
135%   W r i t e U I L I m a g e                                                 %
136%                                                                             %
137%                                                                             %
138%                                                                             %
139%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
140%
141%  Procedure WriteUILImage() writes an image to a file in the X-Motif UIL table
142%  format.
143%
144%  The format of the WriteUILImage method is:
145%
146%      MagickBooleanType WriteUILImage(const ImageInfo *image_info,
147%        Image *image,ExceptionInfo *exception)
148%
149%  A description of each parameter follows.
150%
151%    o image_info: the image info.
152%
153%    o image:  The image.
154%
155%    o exception: return any errors or warnings in this structure.
156%
157*/
158static MagickBooleanType WriteUILImage(const ImageInfo *image_info,Image *image,
159  ExceptionInfo *exception)
160{
161#define MaxCixels  92
162
163  char
164    basename[MagickPathExtent],
165    buffer[MagickPathExtent],
166    name[MagickPathExtent],
167    *symbol;
168
169  int
170    j;
171
172  MagickBooleanType
173    status,
174    transparent;
175
176  MagickSizeType
177    number_pixels;
178
179  PixelInfo
180    pixel;
181
182  register const Quantum
183    *p;
184
185  register ssize_t
186    i,
187    x;
188
189  size_t
190    characters_per_pixel,
191    colors;
192
193  ssize_t
194    k,
195    y;
196
197  static const char
198    Cixel[MaxCixels+1] = " .XoO+@#$%&*=-;:>,<1234567890qwertyuipasdfghjk"
199                         "lzxcvbnmMNBVCZASDFGHJKLPIUYTREWQ!~^/()_`'][{}|";
200
201  /*
202    Open output image file.
203  */
204  assert(image_info != (const ImageInfo *) NULL);
205  assert(image_info->signature == MagickCoreSignature);
206  assert(image != (Image *) NULL);
207  assert(image->signature == MagickCoreSignature);
208  if (image->debug != MagickFalse)
209    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
210  assert(exception != (ExceptionInfo *) NULL);
211  assert(exception->signature == MagickCoreSignature);
212  status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
213  if (status == MagickFalse)
214    return(status);
215  (void) TransformImageColorspace(image,sRGBColorspace,exception);
216  transparent=MagickFalse;
217  i=0;
218  p=(const Quantum *) NULL;
219  if (image->storage_class == PseudoClass)
220    colors=image->colors;
221  else
222    {
223      unsigned char
224        *matte_image;
225
226      /*
227        Convert DirectClass to PseudoClass image.
228      */
229      matte_image=(unsigned char *) NULL;
230      if (image->alpha_trait != UndefinedPixelTrait)
231        {
232          /*
233            Map all the transparent pixels.
234          */
235          number_pixels=(MagickSizeType) image->columns*image->rows;
236          if (number_pixels != ((MagickSizeType) (size_t) number_pixels))
237            ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
238          matte_image=(unsigned char *) AcquireQuantumMemory(image->columns,
239            image->rows*sizeof(*matte_image));
240          if (matte_image == (unsigned char *) NULL)
241            ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
242          for (y=0; y < (ssize_t) image->rows; y++)
243          {
244            p=GetVirtualPixels(image,0,y,image->columns,1,exception);
245            if (p == (const Quantum *) NULL)
246              break;
247            for (x=0; x < (ssize_t) image->columns; x++)
248            {
249              matte_image[i]=(unsigned char) (GetPixelAlpha(image,p) ==
250                (Quantum) TransparentAlpha ? 1 : 0);
251              if (matte_image[i] != 0)
252                transparent=MagickTrue;
253              i++;
254              p+=GetPixelChannels(image);
255            }
256          }
257        }
258      (void) SetImageType(image,PaletteType,exception);
259      colors=image->colors;
260      if (transparent != MagickFalse)
261        {
262          register Quantum
263            *q;
264
265          colors++;
266          for (y=0; y < (ssize_t) image->rows; y++)
267          {
268            q=GetAuthenticPixels(image,0,y,image->columns,1,exception);
269            if (q == (Quantum *) NULL)
270              break;
271            for (x=0; x < (ssize_t) image->columns; x++)
272            {
273              if (matte_image[i] != 0)
274                SetPixelIndex(image,(Quantum) image->colors,q);
275              q+=GetPixelChannels(image);
276            }
277          }
278        }
279      if (matte_image != (unsigned char *) NULL)
280        matte_image=(unsigned char *) RelinquishMagickMemory(matte_image);
281    }
282  /*
283    Compute the character per pixel.
284  */
285  characters_per_pixel=1;
286  for (k=MaxCixels; (ssize_t) colors > k; k*=MaxCixels)
287    characters_per_pixel++;
288  /*
289    UIL header.
290  */
291  symbol=AcquireString("");
292  (void) WriteBlobString(image,"/* UIL */\n");
293  GetPathComponent(image->filename,BasePath,basename);
294  (void) FormatLocaleString(buffer,MagickPathExtent,
295    "value\n  %s_ct : color_table(\n",basename);
296  (void) WriteBlobString(image,buffer);
297  GetPixelInfo(image,&pixel);
298  for (i=0; i < (ssize_t) colors; i++)
299  {
300    /*
301      Define UIL color.
302    */
303    pixel=image->colormap[i];
304    pixel.colorspace=sRGBColorspace;
305    pixel.depth=8;
306    pixel.alpha=(double) OpaqueAlpha;
307    GetColorTuple(&pixel,MagickTrue,name);
308    if (transparent != MagickFalse)
309      if (i == (ssize_t) (colors-1))
310        (void) CopyMagickString(name,"None",MagickPathExtent);
311    /*
312      Write UIL color.
313    */
314    k=i % MaxCixels;
315    symbol[0]=Cixel[k];
316    for (j=1; j < (int) characters_per_pixel; j++)
317    {
318      k=((i-k)/MaxCixels) % MaxCixels;
319      symbol[j]=Cixel[k];
320    }
321    symbol[j]='\0';
322    (void) SubstituteString(&symbol,"'","''");
323    if (LocaleCompare(name,"None") == 0)
324      (void) FormatLocaleString(buffer,MagickPathExtent,
325        "    background color = '%s'",symbol);
326    else
327      (void) FormatLocaleString(buffer,MagickPathExtent,
328        "    color('%s',%s) = '%s'",name,
329        GetPixelInfoIntensity(image,image->colormap+i) <
330        (QuantumRange/2.0) ? "background" : "foreground",symbol);
331    (void) WriteBlobString(image,buffer);
332    (void) FormatLocaleString(buffer,MagickPathExtent,"%s",
333      (i == (ssize_t) (colors-1) ? ");\n" : ",\n"));
334    (void) WriteBlobString(image,buffer);
335  }
336  /*
337    Define UIL pixels.
338  */
339  GetPathComponent(image->filename,BasePath,basename);
340  (void) FormatLocaleString(buffer,MagickPathExtent,
341    "  %s_icon : icon(color_table = %s_ct,\n",basename,basename);
342  (void) WriteBlobString(image,buffer);
343  for (y=0; y < (ssize_t) image->rows; y++)
344  {
345    p=GetVirtualPixels(image,0,y,image->columns,1,exception);
346    if (p == (const Quantum *) NULL)
347      break;
348    (void) WriteBlobString(image,"    \"");
349    for (x=0; x < (ssize_t) image->columns; x++)
350    {
351      k=((ssize_t) GetPixelIndex(image,p) % MaxCixels);
352      symbol[0]=Cixel[k];
353      for (j=1; j < (int) characters_per_pixel; j++)
354      {
355        k=(((int) GetPixelIndex(image,p)-k)/MaxCixels) %
356          MaxCixels;
357        symbol[j]=Cixel[k];
358      }
359      symbol[j]='\0';
360      (void) CopyMagickString(buffer,symbol,MagickPathExtent);
361      (void) WriteBlobString(image,buffer);
362      p+=GetPixelChannels(image);
363    }
364    (void) FormatLocaleString(buffer,MagickPathExtent,"\"%s\n",
365      (y == (ssize_t) (image->rows-1) ? ");" : ","));
366    (void) WriteBlobString(image,buffer);
367    status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
368      image->rows);
369    if (status == MagickFalse)
370      break;
371  }
372  symbol=DestroyString(symbol);
373  (void) CloseBlob(image);
374  return(MagickTrue);
375}
376