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