]> git.saurik.com Git - wxWidgets.git/blob - wxPython/wx/tools/img2py.py
drag-and-drop highlighting
[wxWidgets.git] / wxPython / wx / tools / img2py.py
1 #----------------------------------------------------------------------
2 # Name: wxPython.tools.img2py
3 # Purpose: Convert an image to Python code.
4 #
5 # Author: Robin Dunn
6 #
7 # RCS-ID: $Id$
8 # Copyright: (c) 2002 by Total Control Software
9 # Licence: wxWindows license
10 #----------------------------------------------------------------------
11 # 12/21/2003 - Jeff Grimmett (grimmtooth@softhome.net)
12 #
13 #
14 # 2/25/2007 - Gianluca Costa (archimede86@katamail.com)
15 #
16 #
17 # o V2.5 compatibility update
18 #
19
20 """
21 img2py.py -- Convert an image to PNG format and embed it in a Python
22 module with appropriate code so it can be loaded into
23 a program at runtime. The benefit is that since it is
24 Python source code it can be delivered as a .pyc or
25 'compiled' into the program using freeze, py2exe, etc.
26
27 Usage:
28
29 img2py.py [options] image_file python_file
30
31 Options:
32
33 -m <#rrggbb> If the original image has a mask or transparency defined
34 it will be used by default. You can use this option to
35 override the default or provide a new mask by specifying
36 a colour in the image to mark as transparent.
37
38 -n <name> Normally generic names (getBitmap, etc.) are used for the
39 image access functions. If you use this option you can
40 specify a name that should be used to customize the access
41 fucntions, (getNameBitmap, etc.)
42
43 -c Maintain a catalog of names that can be used to reference
44 images. Catalog can be accessed via catalog and
45 index attributes of the module.
46 If the -n <name> option is specified then <name>
47 is used for the catalog key and index value, otherwise
48 the filename without any path or extension is used
49 as the key.
50
51 -a This flag specifies that the python_file should be appended
52 to instead of overwritten. This in combination with -n will
53 allow you to put multiple images in one Python source file.
54
55 -u Don't use compression. Leaves the data uncompressed.
56
57 -i Also output a function to return the image as a wxIcon.
58
59
60 You can also import this module from your Python scripts, and use its img2py()
61 function. See its docstring for more info.
62 """
63
64 #
65 # Changes:
66 # - Cliff Wells <LogiplexSoftware@earthlink.net>
67 # 20021206: Added catalog (-c) option.
68 #
69 # 12/21/2003 - Jeff Grimmett (grimmtooth@softhome.net)
70 #
71 #
72 # 2/25/2007 - Gianluca Costa (archimede86@katamail.com)
73 # -Refactorization of the script-creation code in a specific "img2py()" function
74 # -Added regex parsing instead of module importing
75 # -Added some "try/finally" statements
76 # -Added default values as named constants
77 # -Made some parts of code a bit easier to read
78 # -Updated the module docstring
79 # -Corrected a bug with EmptyIcon
80 #
81 # o V2.5 compatibility update
82 #
83 import cPickle
84 import cStringIO
85 import getopt
86 import glob
87 import os
88 import os.path
89 import sys
90 import tempfile
91 import zlib
92 import re
93
94 import wx
95 import img2img
96
97
98 def crunch_data(data, compressed):
99 # compress it?
100 if compressed:
101 data = zlib.compress(data, 9)
102
103 # convert to a printable format, so it can be in a Python source file
104 data = repr(data)
105
106 # This next bit is borrowed from PIL. It is used to wrap the text intelligently.
107 fp = cStringIO.StringIO()
108 data += " " # buffer for the +1 test
109 c = i = 0
110 word = ""
111 octdigits = "01234567"
112 hexdigits = "0123456789abcdef"
113 while i < len(data):
114 if data[i] != "\\":
115 word = data[i]
116 i += 1
117 else:
118 if data[i+1] in octdigits:
119 for n in xrange(2, 5):
120 if data[i+n] not in octdigits:
121 break
122 word = data[i:i+n]
123 i += n
124 elif data[i+1] == 'x':
125 for n in xrange(2, 5):
126 if data[i+n] not in hexdigits:
127 break
128 word = data[i:i+n]
129 i += n
130 else:
131 word = data[i:i+2]
132 i += 2
133
134 l = len(word)
135 if c + l >= 78-1:
136 fp.write("\\\n")
137 c = 0
138 fp.write(word)
139 c += l
140
141 # return the formatted compressed data
142 return fp.getvalue()
143
144
145 app = None
146 DEFAULT_APPEND = False
147 DEFAULT_COMPRESSED = True
148 DEFAULT_MASKCLR = None
149 DEFAULT_IMGNAME = ""
150 DEFAULT_ICON = False
151 DEFAULT_CATALOG = False
152
153 #THIS IS USED TO IDENTIFY, IN THE GENERATED SCRIPT, LINES IN THE FORM "index.append('Image name')"
154 indexPattern = re.compile(r"\s*index.append\('(.+)'\)\s*")
155
156 def img2py(image_file, python_file, append=DEFAULT_APPEND, compressed=DEFAULT_COMPRESSED, maskClr=DEFAULT_MASKCLR, imgName=DEFAULT_IMGNAME, icon=DEFAULT_ICON, catalog=DEFAULT_CATALOG):
157 """
158 Converts an image file to a data structure written in a Python file
159 --image_file: string; the path of the source image file
160 --python_file: string; the path of the destination python file
161 --other arguments: they are equivalent to the command-line arguments
162 """
163 global app
164 if not wx.GetApp():
165 app = wx.PySimpleApp()
166
167 # convert the image file to a temporary file
168 tfname = tempfile.mktemp()
169 try:
170 ok, msg = img2img.convert(image_file, maskClr, None, tfname, wx.BITMAP_TYPE_PNG, ".png")
171 if not ok:
172 print msg
173 return
174
175 data = open(tfname, "rb").read()
176 data = crunch_data(data, compressed)
177 finally:
178 if os.path.exists(tfname):
179 os.remove(tfname)
180
181
182 old_index = []
183 if catalog and append:
184 # check to see if catalog exists already (file may have been created
185 # with an earlier version of img2py or without -c option)
186 pyPath, pyFile = os.path.split(python_file)
187
188 append_catalog = True
189
190 sourcePy = open(python_file, "r")
191 try:
192 for line in sourcePy:
193
194 if line == "catalog = {}\n":
195 append_catalog = False
196 else:
197 lineMatcher = indexPattern.match(line)
198 if lineMatcher:
199 old_index.append(lineMatcher.groups()[0])
200 finally:
201 sourcePy.close()
202
203
204 if append_catalog:
205 out = open(python_file, "a")
206 try:
207 out.write("\n# ***************** Catalog starts here *******************")
208 out.write("\n\ncatalog = {}\n")
209 out.write("index = []\n\n")
210 out.write("class ImageClass: pass\n\n")
211 finally:
212 out.close()
213
214
215
216 if append:
217 out = open(python_file, "a")
218 else:
219 out = open(python_file, "w")
220
221 try:
222 if catalog:
223 imgPath, imgFile = os.path.split(image_file)
224
225 if not imgName:
226 imgName = os.path.splitext(imgFile)[0]
227 print "\nWarning: -n not specified. Using filename (%s) for catalog entry." % imgName
228
229 out.write("#" + "-" * 70 + "\n")
230 if not append:
231 out.write("# This file was generated by %s\n#\n" % sys.argv[0])
232 out.write("from wx import ImageFromStream, BitmapFromImage, EmptyIcon\n")
233 if compressed:
234 out.write("import cStringIO, zlib\n\n\n")
235 else:
236 out.write("import cStringIO\n\n\n")
237
238 if catalog:
239 out.write("catalog = {}\n")
240 out.write("index = []\n\n")
241 out.write("class ImageClass: pass\n\n")
242
243 if compressed:
244 out.write("def get%sData():\n"
245 " return zlib.decompress(\n%s)\n\n"
246 % (imgName, data))
247 else:
248 out.write("def get%sData():\n"
249 " return \\\n%s\n\n"
250 % (imgName, data))
251
252
253 out.write("def get%sBitmap():\n"
254 " return BitmapFromImage(get%sImage())\n\n"
255 "def get%sImage():\n"
256 " stream = cStringIO.StringIO(get%sData())\n"
257 " return ImageFromStream(stream)\n\n"
258 % tuple([imgName] * 4))
259 if icon:
260 out.write("def get%sIcon():\n"
261 " icon = EmptyIcon()\n"
262 " icon.CopyFromBitmap(get%sBitmap())\n"
263 " return icon\n\n"
264 % tuple([imgName] * 2))
265
266 if catalog:
267 if imgName in old_index:
268 print "Warning: %s already in catalog." % imgName
269 print " Only the last entry will be accessible.\n"
270 old_index.append(imgName)
271 out.write("index.append('%s')\n" % imgName)
272 out.write("catalog['%s'] = ImageClass()\n" % imgName)
273 out.write("catalog['%s'].getData = get%sData\n" % tuple([imgName] * 2))
274 out.write("catalog['%s'].getImage = get%sImage\n" % tuple([imgName] * 2))
275 out.write("catalog['%s'].getBitmap = get%sBitmap\n" % tuple([imgName] * 2))
276 if icon:
277 out.write("catalog['%s'].getIcon = get%sIcon\n" % tuple([imgName] * 2))
278 out.write("\n\n")
279
280
281 if imgName:
282 n_msg = ' using "%s"' % imgName
283 else:
284 n_msg = ""
285
286 if maskClr:
287 m_msg = " with mask %s" % maskClr
288 else:
289 m_msg = ""
290
291 print "Embedded %s%s into %s%s" % (image_file, n_msg, python_file, m_msg)
292 finally:
293 out.close()
294
295
296
297 def main(args):
298 if not args or ("-h" in args):
299 print __doc__
300 return
301
302 append = DEFAULT_APPEND
303 compressed = DEFAULT_COMPRESSED
304 maskClr = DEFAULT_MASKCLR
305 imgName = DEFAULT_IMGNAME
306 icon = DEFAULT_ICON
307 catalog = DEFAULT_CATALOG
308
309 try:
310 opts, fileArgs = getopt.getopt(args, "auicn:m:")
311 except getopt.GetoptError:
312 print __doc__
313 return
314
315 for opt, val in opts:
316 if opt == "-a":
317 append = True
318 elif opt == "-u":
319 compressed = False
320 elif opt == "-n":
321 imgName = val
322 elif opt == "-m":
323 maskClr = val
324 elif opt == "-i":
325 icon = True
326 elif opt == "-c":
327 catalog = True
328
329 if len(fileArgs) != 2:
330 print __doc__
331 return
332
333 image_file, python_file = fileArgs
334 img2py(image_file, python_file, append, compressed, maskClr, imgName, icon, catalog)
335
336
337
338 if __name__ == "__main__":
339 main(sys.argv[1:])