1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        src/common/imagxpm.cpp
3 // Purpose:     wxXPMHandler
4 // Author:      Vaclav Slavik, Robert Roebling
5 // RCS-ID:      $Id: imagxpm.cpp 53477 2008-05-07 07:28:57Z JS $
6 // Copyright:   (c) 2001 Vaclav Slavik
7 // Licence:     wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
9 
10 /*
11 
12 This file is partially based on source code of ImageMagick by John Cristy. Its
13 license is as follows:
14 
15 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
16 %                                                                             %
17 %                                                                             %
18 %                                                                             %
19 %                            X   X  PPPP   M   M                              %
20 %                             X X   P   P  MM MM                              %
21 %                              X    PPPP   M M M                              %
22 %                             X X   P      M   M                              %
23 %                            X   X  P      M   M                              %
24 %                                                                             %
25 %                                                                             %
26 %                    Read/Write ImageMagick Image Format.                     %
27 %                                                                             %
28 %                                                                             %
29 %                              Software Design                                %
30 %                                John Cristy                                  %
31 %                                 July 1992                                   %
32 %                                                                             %
33 %                                                                             %
34 %  Copyright (C) 2001 ImageMagick Studio, a non-profit organization dedicated %
35 %  to making software imaging solutions freely available.                     %
36 %                                                                             %
37 %  Permission is hereby granted, free of charge, to any person obtaining a    %
38 %  copy of this software and associated documentation files ("ImageMagick"),  %
39 %  to deal in ImageMagick without restriction, including without limitation   %
40 %  the rights to use, copy, modify, merge, publish, distribute, sublicense,   %
41 %  and/or sell copies of ImageMagick, and to permit persons to whom the       %
42 %  ImageMagick is furnished to do so, subject to the following conditions:    %
43 %                                                                             %
44 %  The above copyright notice and this permission notice shall be included in %
45 %  all copies or substantial portions of ImageMagick.                         %
46 %                                                                             %
47 %  The software is provided "as is", without warranty of any kind, express or %
48 %  implied, including but not limited to the warranties of merchantability,   %
49 %  fitness for a particular purpose and noninfringement.  In no event shall   %
50 %  ImageMagick Studio be liable for any claim, damages or other liability,    %
51 %  whether in an action of contract, tort or otherwise, arising from, out of  %
52 %  or in connection with ImageMagick or the use or other dealings in          %
53 %  ImageMagick.                                                               %
54 %                                                                             %
55 %  Except as contained in this notice, the name of the ImageMagick Studio     %
56 %  shall not be used in advertising or otherwise to promote the sale, use or  %
57 %  other dealings in ImageMagick without prior written authorization from the %
58 %  ImageMagick Studio.                                                        %
59 %                                                                             %
60 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
61 %
62 %
63 */
64 
65 // For compilers that support precompilation, includes "wx.h".
66 #include "wx/wxprec.h"
67 
68 #ifdef __BORLANDC__
69     #pragma hdrstop
70 #endif
71 
72 #if wxUSE_XPM
73 
74 #ifndef WX_PRECOMP
75     #include "wx/log.h"
76     #include "wx/intl.h"
77     #include "wx/utils.h"
78 #endif
79 
80 #include "wx/imagxpm.h"
81 #include "wx/wfstream.h"
82 #include "wx/xpmdecod.h"
83 
IMPLEMENT_DYNAMIC_CLASS(wxXPMHandler,wxImageHandler)84 IMPLEMENT_DYNAMIC_CLASS(wxXPMHandler,wxImageHandler)
85 
86 //-----------------------------------------------------------------------------
87 // wxXPMHandler
88 //-----------------------------------------------------------------------------
89 
90 #if wxUSE_STREAMS
91 
92 bool wxXPMHandler::LoadFile(wxImage *image,
93                             wxInputStream& stream,
94                             bool WXUNUSED(verbose), int WXUNUSED(index))
95 {
96     wxXPMDecoder decoder;
97 
98     wxImage img = decoder.ReadFile(stream);
99     if ( !img.Ok() )
100         return false;
101     *image = img;
102     return true;
103 }
104 
SaveFile(wxImage * image,wxOutputStream & stream,bool WXUNUSED (verbose))105 bool wxXPMHandler::SaveFile(wxImage * image,
106                             wxOutputStream& stream, bool WXUNUSED(verbose))
107 {
108     // 1. count colours:
109     #define MaxCixels  92
110     static const char Cixel[MaxCixels+1] =
111                          " .XoO+@#$%&*=-;:>,<1234567890qwertyuipasdfghjk"
112                          "lzxcvbnmMNBVCZASDFGHJKLPIUYTREWQ!~^/()_`'][{}|";
113     int i, j, k;
114 
115     wxImageHistogram histogram;
116     int cols = int(image->ComputeHistogram(histogram));
117 
118     int chars_per_pixel = 1;
119     for ( k = MaxCixels; cols > k; k *= MaxCixels)
120         chars_per_pixel++;
121 
122     // 2. write the header:
123     wxString sName;
124     if ( image->HasOption(wxIMAGE_OPTION_FILENAME) )
125     {
126         wxSplitPath(image->GetOption(wxIMAGE_OPTION_FILENAME),
127                     NULL, &sName, NULL);
128         sName << wxT("_xpm");
129     }
130 
131     if ( !sName.empty() )
132         sName = wxString(wxT("/* XPM */\nstatic const char *")) + sName;
133     else
134         sName = wxT("/* XPM */\nstatic const char *xpm_data");
135     stream.Write( (const char*) sName.ToAscii(), sName.Len() );
136 
137     char tmpbuf[200];
138     // VS: 200b is safe upper bound for anything produced by sprintf below
139     //     (<101 bytes the string, neither %i can expand into more than 10 chars)
140     sprintf(tmpbuf,
141                "[] = {\n"
142                "/* columns rows colors chars-per-pixel */\n"
143                "\"%i %i %i %i\",\n",
144                image->GetWidth(), image->GetHeight(), cols, chars_per_pixel);
145     stream.Write(tmpbuf, strlen(tmpbuf));
146 
147     // 3. create color symbols table:
148     char *symbols_data = new char[cols * (chars_per_pixel+1)];
149     char **symbols = new char*[cols];
150 
151     // 2a. find mask colour:
152     unsigned long mask_key = 0x1000000 /*invalid RGB value*/;
153     if (image->HasMask())
154         mask_key = (image->GetMaskRed() << 16) |
155                    (image->GetMaskGreen() << 8) | image->GetMaskBlue();
156 
157     // 2b. generate colour table:
158     for (wxImageHistogram::iterator entry = histogram.begin();
159          entry != histogram.end(); ++entry )
160     {
161         unsigned long index = entry->second.index;
162         symbols[index] = symbols_data + index * (chars_per_pixel+1);
163         char *sym = symbols[index];
164 
165         for (j = 0; j < chars_per_pixel; j++)
166         {
167             sym[j] = Cixel[index % MaxCixels];
168             index /= MaxCixels;
169         }
170         sym[j] = '\0';
171 
172         unsigned long key = entry->first;
173 
174         if (key == 0)
175             sprintf( tmpbuf, "\"%s c Black\",\n", sym);
176         else if (key == mask_key)
177             sprintf( tmpbuf, "\"%s c None\",\n", sym);
178         else
179         {
180             wxByte r = wxByte(key >> 16);
181             wxByte g = wxByte(key >> 8);
182             wxByte b = wxByte(key);
183             sprintf(tmpbuf, "\"%s c #%02X%02X%02X\",\n", sym, r, g, b);
184         }
185         stream.Write( tmpbuf, strlen(tmpbuf) );
186     }
187 
188     stream.Write("/* pixels */\n", 13);
189 
190     unsigned char *data = image->GetData();
191     for (j = 0; j < image->GetHeight(); j++)
192     {
193         char tmp_c;
194         tmp_c = '\"'; stream.Write(&tmp_c, 1);
195         for (i = 0; i < image->GetWidth(); i++, data += 3)
196         {
197             unsigned long key = (data[0] << 16) | (data[1] << 8) | (data[2]);
198             stream.Write(symbols[histogram[key].index], chars_per_pixel);
199         }
200         tmp_c = '\"'; stream.Write(&tmp_c, 1);
201         if ( j + 1 < image->GetHeight() )
202         {
203             tmp_c = ','; stream.Write(&tmp_c, 1);
204         }
205         tmp_c = '\n'; stream.Write(&tmp_c, 1);
206     }
207     stream.Write("};\n", 3 );
208 
209     // Clean up:
210     delete[] symbols;
211     delete[] symbols_data;
212 
213     return true;
214 }
215 
DoCanRead(wxInputStream & stream)216 bool wxXPMHandler::DoCanRead(wxInputStream& stream)
217 {
218     wxXPMDecoder decoder;
219     return decoder.CanRead(stream);
220 }
221 
222 #endif  // wxUSE_STREAMS
223 
224 #endif // wxUSE_XPM
225