]> git.saurik.com Git - wxWidgets.git/blame - wxPython/wx/tools/img2py.py
fixes to wint_t and wchar_t handling in unichar.h (fixes FreeBSD compilation and...
[wxWidgets.git] / wxPython / wx / tools / img2py.py
CommitLineData
d14a1e28
RD
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#----------------------------------------------------------------------
d4b73b1b
RD
11# 12/21/2003 - Jeff Grimmett (grimmtooth@softhome.net)
12#
d4b73b1b 13#
cbfc9df6
RD
14# 2/25/2007 - Gianluca Costa (archimede86@katamail.com)
15#
16#
17# o V2.5 compatibility update
18#
1fded56b 19
d14a1e28
RD
20"""
21img2py.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
27Usage:
28
29 img2py.py [options] image_file python_file
30
31Options:
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
cbfc9df6
RD
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>
d14a1e28 47 is used for the catalog key and index value, otherwise
cbfc9df6
RD
48 the filename without any path or extension is used
49 as the key.
d14a1e28
RD
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
cbfc9df6
RD
59
60You can also import this module from your Python scripts, and use its img2py()
61function. See its docstring for more info.
d14a1e28
RD
62"""
63
64#
65# Changes:
66# - Cliff Wells <LogiplexSoftware@earthlink.net>
67# 20021206: Added catalog (-c) option.
68#
d4b73b1b
RD
69# 12/21/2003 - Jeff Grimmett (grimmtooth@softhome.net)
70#
d4b73b1b 71#
cbfc9df6
RD
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#
d4b73b1b
RD
83import cPickle
84import cStringIO
85import getopt
86import glob
87import os
cbfc9df6 88import os.path
d4b73b1b
RD
89import sys
90import tempfile
91import zlib
cbfc9df6 92import re
d14a1e28 93
d4b73b1b 94import wx
d4b73b1b 95import img2img
d14a1e28
RD
96
97
98def 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()
cbfc9df6 108 data += " " # buffer for the +1 test
d14a1e28
RD
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]
cbfc9df6 116 i += 1
d14a1e28
RD
117 else:
118 if data[i+1] in octdigits:
cbfc9df6 119 for n in xrange(2, 5):
d14a1e28
RD
120 if data[i+n] not in octdigits:
121 break
122 word = data[i:i+n]
cbfc9df6 123 i += n
d14a1e28 124 elif data[i+1] == 'x':
cbfc9df6 125 for n in xrange(2, 5):
d14a1e28
RD
126 if data[i+n] not in hexdigits:
127 break
128 word = data[i:i+n]
cbfc9df6 129 i += n
d14a1e28
RD
130 else:
131 word = data[i:i+2]
cbfc9df6 132 i += 2
d14a1e28
RD
133
134 l = len(word)
135 if c + l >= 78-1:
136 fp.write("\\\n")
137 c = 0
138 fp.write(word)
cbfc9df6 139 c += l
d14a1e28
RD
140
141 # return the formatted compressed data
142 return fp.getvalue()
143
144
2240b1aa 145app = None
cbfc9df6
RD
146DEFAULT_APPEND = False
147DEFAULT_COMPRESSED = True
148DEFAULT_MASKCLR = None
149DEFAULT_IMGNAME = ""
150DEFAULT_ICON = False
151DEFAULT_CATALOG = False
152
153#THIS IS USED TO IDENTIFY, IN THE GENERATED SCRIPT, LINES IN THE FORM "index.append('Image name')"
154indexPattern = re.compile(r"\s*index.append\('(.+)'\)\s*")
155
156def 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
d14a1e28
RD
297def main(args):
298 if not args or ("-h" in args):
299 print __doc__
300 return
cbfc9df6
RD
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
d14a1e28
RD
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":
cbfc9df6 317 append = True
d14a1e28 318 elif opt == "-u":
cbfc9df6 319 compressed = False
d14a1e28
RD
320 elif opt == "-n":
321 imgName = val
322 elif opt == "-m":
323 maskClr = val
324 elif opt == "-i":
cbfc9df6 325 icon = True
d14a1e28 326 elif opt == "-c":
cbfc9df6 327 catalog = True
d14a1e28
RD
328
329 if len(fileArgs) != 2:
330 print __doc__
331 return
332
333 image_file, python_file = fileArgs
cbfc9df6
RD
334 img2py(image_file, python_file, append, compressed, maskClr, imgName, icon, catalog)
335
d14a1e28 336
cbfc9df6 337
d14a1e28
RD
338if __name__ == "__main__":
339 main(sys.argv[1:])