Attachment 'Image2PyFile.py'
Download 1 """
2 Img2PyFile.py
3
4 Convert an image to b64 string format and embed it in a Python module
5 with appropriate code so it can be imported into a program at runtime.
6
7 Derived from img2py.py by Robin Dunn.
8 img2py.py crashes on Win7 64-bit as of 2012-04-26.
9
10 Usage:
11 import Img2PyFile as i2p
12 i2p.Img2PyFile( [options] imgFile1 [ imgFile2 ...] \
13 [ pyImagesExist1.py ...] pyImagesNew.py )
14
15 Arguments for image files, options and pyImages files
16 may intermixed in any order.
17 The last given pyImages file will always be written or
18 or **appended to** if it already exists.
19
20 PROGRESS, NOTE and WARNING message are written to stdout.
21
22 FAILURE messages indicate file read or write failures.
23 They do NOT end the application execution.
24
25 ERROR messages indicate a fatal application error.
26 They cannot be suppressed, thus there are no associated
27 command line options available.
28
29 Options: (NOTE: None of these options *need* to be specified.)
30
31 -a -A Enable/Disable ACTION messages. Disabled by default.
32 -f -F Enable/Disable FAULURE messages. Enabled by default.
33 -n -N Enable/Disable NOTE: messages. Disabled by default.
34 -p -P Enable/Disable PROGRESS messages. Enabled by default.
35 -w -W Enable/Disable WARNING messages. Disabled by default.
36
37 -q Suppress all nonfatal messages.
38 To enable only specific messages specify '-q' then follow
39 with the desired lower case message options.
40
41 -h List this help and exit.
42 -H List this help THEN CONTINUE.
43
44 A PROGRESS message indicates an attempt to do something
45 such as read a file while an ACTION message indicates
46 the actual success at doing something.
47
48 This module can be used internally by instantiating
49 an Img2PyFile() class object.
50
51 E.g., the following:
52
53 - Disables all messaging except for PROGRESS messages;
54 - Reads all existing image data from file pyimagesIn.py and
55 - appends them to file pyimagesOut.py;
56 - Processes images from all give .PNG files and writes their
57 data to pyimagesOut.py
58
59 import Img2PyFile as i2p
60 args = '-qp image1.png pyimagesIn.py pyImagesOut.py image2.gif'
61 args = args.split() # Args are in a list just like sys.argv[ 1: ]
62 i2p.Img2PyFile( args )
63
64 E.g.:
65 An initial command line runs and its results when file PyImages.PY
66 does not yet exist:
67
68 > python.exe Image2PyFile.py About-16.PNG About-32.PNG PyImages.PY
69 PROGRESS: Reading New Image Files
70 ACTION: Adding Image: [ About_16_PNG ] File: [ About-16.PNG]
71 ACTION: Adding Image: [ About_32_PNG ] File: [ About-32.PNG]
72 PROGRESS: Writing New PyImages File: [ PyImages.PY ]
73
74 A following run when file PyImages.PY does exist:
75
76 > python.exe Image2PyFile.py Cut-32.PNG Delete-16.PNG
77 PROGRESS: Reading Existing PyImages File: [ PyImages.PY ]
78 PROGRESS: Reading New Image Files
79 ACTION: Adding Image: [ Cut_32_PNG ] File: [ Cut-32.PNG]
80 ACTION: Adding Image: [ Delete_16_PNG ] File: [ Delete-16.PNG]
81 PROGRESS: OVERWRITING PyImages File: [ PyImages.PY ]
82
83
84 Ray Pasco
85 pascor(at)verizon(dot)net
86
87 Version:
88 1.1 2012-04-26
89
90 Tested on:
91
92 Windows 6.1.7601 {Windows 7 64-bit}
93 Python 2.6.5 (r265:79096, Mar 19 2010, 21:48:26) [MSC v.1500 32 bit (Intel)]
94 Wx Version 2.8.12.0
95 Wx Pltform ('__WXMSW__', 'wxMSW', 'unicode', 'wx-assertions-on', 'SWIG-1.3.29')
96
97 Windows 5.1.2600 {Windows XP 32-bit}
98 Python 2.6.5 (r265:79096, Mar 19 2010, 21:48:26) [MSC v.1500 32 bit (Intel)]
99 Wx Version 2.8.12.0
100 Wx Pltform ('__WXMSW__', 'wxMSW', 'unicode', 'wx-assertions-on', 'SWIG-1.3.29')
101 """
102
103 import getopt
104 import glob
105 import os, sys
106 import re
107 import tempfile
108 import base64
109 import binascii
110 import wx
111
112 scriptName = sys.argv[ 0 ]
113
114 #------------------------------------------------------------------------------
115
116 def CallersName():
117 return sys._getframe(2).f_code.co_name
118
119 #------------------------------------------------------------------------------
120
121 # Credit to Alex Martelli, "Python Cookbook" p. 440
122 def DefName() :
123 """
124 Returns the name of the function calling DefName().
125 Does not work inside class __init__() definitions.
126 """
127 import sys
128 return sys._getframe(1).f_code.co_name + '()'
129
130 #end def
131
132 #------------------------------------------------------------------------------
133
134 def WhatsInstalled() :
135 """
136 List the versions of Python and wxPython.
137 """
138 defName = DefName() # For DEBUG
139
140 # Which vesrions of Python and wxPython are installed ?
141 import os, sys, platform
142 print
143 print defName + '():'
144 if os.name == 'nt' :
145 print 'Windows ', platform.win32_ver()[1]
146 else :
147 print 'Platform ', platform.system()
148 #end if
149 print 'Python ', sys.version
150 addon_pkgs = [ ('Wx Version', 'wx.VERSION_STRING'),
151 ('Wx Pltform', 'wx.PlatformInfo'), ]
152
153 for addonStr, attribute in addon_pkgs :
154 try :
155 print addonStr, eval( attribute )
156 except NameError :
157 print
158 #end try
159 #end for
160 print
161
162 #end WhatsInstalled def
163
164 #------------------------------------------------------------------------------
165
166 def String2Identifier( s ) :
167 """
168 Simple character substitution to produce a legal Python identifier string.
169 """
170 defName = DefName() # For DEBUG
171
172 letters = []
173 for letter in s :
174 if not letter.isalnum() :
175 letter = '_'
176 letters.append( letter )
177 #end for
178
179 if not letters[ 0 ].isalpha() and letters[ 0 ] != '_' :
180 letters.insert( 0, '_' )
181 identifierString = ''.join( letters )
182
183 return identifierString
184
185 #end String2Identifier def
186
187 #------------------------------------------------------------------------------
188
189 def ProcessArgs( args=None ) :
190 """
191 Command line parsing. Separates args into three groups:
192 1) List if pyImages files that will be read and/or written
193 2) A list set() names indicating which kinds of message
194 will be printed.
195 """
196 defName = DefName() # For DEBUG
197
198 if not args :
199 msg = 'ERROR: %s::%s: No Commandline Args Given\n' \
200 %( scriptName, defName )
201 print >> sys.stderr, msg
202 print >> sys.stderr, __doc__
203 sys.exit(1)
204 #end if
205
206 #-----
207
208 try :
209 opts, fileArgs = getopt.gnu_getopt( args, 'aA fF hH nN pP q wW' )
210
211 except getopt.GetoptError :
212
213 msg = '\nERROR: %s::%s: UNKNOWN SWITCH ARG in:\n\n%s\n' \
214 %( scriptName, defName, args )
215 print >> sys.stderr, msg
216 sys.exit(1)
217
218 #-----
219
220 # [ opts ] is returned as a hard-to-mutate list of tuples.
221 enabledMsgs = set( [ 'action', 'progress' ] )
222 for key, valIgnored in opts :
223
224 if key == '-a' :
225 enabledMsgs.add( 'action' ) # Enable these messages
226 elif key == '-A' :
227 enabledMsgs.discard( 'action' ) # Suppress these messages
228
229 elif key == '-f' :
230 enabledMsgs.add( 'failure' )
231 elif key == '-F' :
232 enabledMsgs.discard( 'failure' )
233
234 elif key == '-h' :
235 print __doc__
236 sys.exit(1)
237 elif key == '-H' :
238 print __doc__
239
240 elif key == '-n' :
241 enabledMsgs.add( 'note' )
242 elif key == '-N' :
243 enabledMsgs.discard( 'note' )
244
245 elif key == '-p' :
246 enabledMsgs.add( 'progress' )
247 elif key == '-P' :
248 enabledMsgs.discard( 'progress' )
249
250 elif key == '-q' :
251 enabledMsgs = list() # Suppress all messages
252
253 elif key == '-w' :
254 enabledMsgs.add( 'warning' )
255 elif key == '-W' :
256 enabledMsgs.discard( 'warning' )
257
258 else :
259 print >> sys.stderr, 'UNRECOGNIZED Arg Switch [ %s ]' %( key )
260 #end if
261
262 #end for
263 ##print 'enabledMsgs: ', enabledMsgs; print # DEBUG
264
265 # Sanity check.
266 if len( fileArgs ) < 1 :
267
268 msg = '\nERROR - %s::%s: At Least One PyImages Filename Must Be Given.\n' \
269 %( scriptName, defName )
270 print >> sys.stderr, msg
271 sys.exit(1)
272
273 #end if
274
275 #-----
276
277 return (enabledMsgs, fileArgs)
278
279 #end ProcessArgs
280
281 #------------------------------------------------------------------------------
282
283 def B64Encode( s, altchars=None ) :
284 """
285 Encode a string using Base64.
286
287 Optional altchars must be a string of at least length 2 (additional
288 characters are ignored) which specifies an alternative alphabet for
289 the '+' and '/' characters. This allows an application, e.g.,
290 to generate a url or filesystem-safe Base64 strings.
291
292 The encoded string is returned.
293 """
294 defName = DefName() # For DEBUG
295
296 # Eliminate the trailing newline returned.
297 encoded = binascii.b2a_base64( s )[ :-1 ]
298
299 if altchars :
300 encoded = _translate( encoded, {'+': altchars[0], '/': altchars[1]} )
301
302 return encoded
303
304 #end B64Encode def
305
306 #------------------------------------------------------------------------------
307
308 def BitmapToPngFile( wxBmap, outputDir=None, outputName='', enabledMsgs=None ) :
309 """
310 Save a wx.Bitmap to a PNG file. The contents of this file is intended
311 to be b64 encoded in order to finally save it to the output pyImages file.
312 """
313 defName = DefName() # For DEBUG
314
315 if outputName :
316 outFilePathname = outputName
317
318 else :
319
320 newMainName = os.path.basename( os.path.splitext( imgFilename )[0] )
321 newfileBasename = newMainName + '.png'
322 outFilePathname = os.path.join( outputDir, newfileBasename )
323 #end if
324
325 if wxBmap.SaveFile( outFilePathname, wx.BITMAP_TYPE_PNG ) : # SaveFile() success
326
327 return True
328
329 else : # wx.Bitmap.SaveFile() has failed.
330 if ('failure' in enabledMsgs) :
331 msg = '\nFAILURE: CAN\'T WRITE Temporary wx.Bitmap to .PNG file.\n'
332 print >> sys.stderr, msg
333 #end if
334
335 # Try a different save tactic.
336 wxImage = wx.ImageFromBitmap( wxBmap ) # ? Avoid some early wx version limitation ?
337 if wxImage.SaveFile( outFilePathname, wx.BITMAP_TYPE_PNG ) :
338 return True
339
340 else :
341 msg = '\nERROR: CAN\'T WRITE Temporary wx.Image to.PNG File: [ %s ]\n\n' \
342 %( outFilePathname )
343 print >> sys.stderr, msg
344 sys.exit(1)
345 #end if
346
347 #end if wxBmap.SaveFile()
348
349 #end BitmapToPngFile def
350
351 #------------------------------------------------------------------------------
352
353 def CreatePngFileData( imgFilename, enabledMsgs ) :
354 """
355
356 """
357 defName = DefName() # For DEBUG
358
359 if not os.path.exists( imgFilename ) :
360 if ('warning' in enabledMsgs) :
361 msg = '\nWARNING: Image File Doesn\'t Exist[ %s ].' %( imgFilename )
362 print msg
363
364 return None
365 #end if
366
367 msg = '\nFAILURE: Image File is UNREADABLE [ %s ]' %( imgFilename )
368 try :
369 wxBmap = wx.Bitmap( imgFilename, wx.BITMAP_TYPE_ANY )
370
371 except :
372 if ('failure' in enabledMsgs) :
373 print >> sys.stderr, msg
374 return None
375
376 #-----
377
378 # Handle bad image file data
379 if (not wxBmap.Ok()) and ('failure' in enabledMsgs) :
380 print >> sys.stderr, msg
381 ##print '5'*70 # DEBUG
382 return None
383
384 #end if
385
386 #-----
387
388 # Read the original image file and write it to a new PNG file.
389 tmpPngFilename = tempfile.mktemp()
390
391 success = BitmapToPngFile( wxBmap, None, tmpPngFilename, enabledMsgs )
392 if not success :
393 print >> sys.stderr, '\nERROR: CAN\'T WRITE to Temporary PNG File.\n' \
394 %( scriptName, defName )
395 return None
396
397 #-----
398
399 #-----
400
401 # Encode the PNG file's lossless-compressed binary image data into a single, big b64 string.
402 pngFile = open( tmpPngFilename, 'rb' )
403 pngImageData = pngFile.read()
404 pngFile.close()
405 os.remove( tmpPngFilename )
406
407 return pngImageData
408
409 #end CreatePngFileData def
410
411 #------------------------------------------------------------------------------
412
413 def B64EncodeBinaryData( pngImageData ) :
414 """
415 B64 encodes a binary byte string. Returns a list of lines of strings
416 suitable for embedding in a Python file.
417 """
418 defName = DefName() # For DEBUG
419
420 # Encode the PNG file's lossless-compressed binary image data into a single, big b64 string.
421 encPngImgData = B64Encode( pngImageData )
422
423 # Chop the long b64 character-encoded encPngImgData into manageable
424 # line lengths for writing to a file.
425 linesOfEncPngImgData = list() # b64 linesOfEncPngImgData list.
426 while encPngImgData :
427
428 aLineOfEncPngImgData = encPngImgData[ :72 ] # A chunk length of 72 chars
429 encPngImgData = encPngImgData[ 72: ] # The remainder of data to be encoded.
430 aLineOfEncPngImgData = ' "%s"' %( aLineOfEncPngImgData )
431
432 linesOfEncPngImgData.append( aLineOfEncPngImgData ) # Add to linesOfEncPngImgData list.
433
434 #end while encPngImgData
435 linesOfEncPngImgData = '\n'.join( linesOfEncPngImgData )
436
437 return linesOfEncPngImgData
438
439 #end B64EncodeBinaryData def
440
441 #------------------------------------------------------------------------------
442
443 class ImageObject() :
444 """
445 Image data storage. A collection of the most useful attributes
446 for both reading images from existing pyImages files and
447 also for generating a new output file.
448 """
449
450 def __init__( self, idName='', baseName='', mainName='', fileExt='', encPngData='' ) :
451 defName = 'ImageObject()'
452
453 # Init the attributes. Null ones will be defined shortly.
454 self.idName = idName # Suitable for use as a Python identifier.
455 self.baseName = baseName # The image's source file basename.
456 self.mainName = mainName # The "main" part of the source basename
457 self.fileExt = fileExt # The extension part of the source basename
458 self.createdExt = False # First assume a baseName was originally supplied.
459 self.encPngData = encPngData # Image's .PNG file binary data
460
461 # All the most common 3-letter image file extensions.
462 # FUTURE: jpeg, tiff, any other non-3-letter image file extensions (if there are any).
463 IMG_EXTS = [ '.bmp', '.gif', '.ico', '.jpg', '.png', '.tif' ]
464
465 if baseName : # [is given] File extension may or may not be appended.
466
467 extLen = 4 # Includes the leading period.
468 extStartIndex = len( self.baseName ) - extLen
469
470 # Is the file extension is appended ?
471 if self.baseName.lower()[ extStartIndex: ] in IMG_EXTS :
472
473 self.mainName, self.fileExt = os.path.splitext( baseName )
474
475 else : # File extension is not appended.
476
477 self.mainName = self.baseName
478 self.fileExt = '.png'
479 self.createdExt = True
480 self.baseName = self.baseName + self.fileExt
481
482 #end if
483
484 elif self.mainName : # [is given] Has no fileExt
485
486 if self.fileExt : # The fileExt is defined - create the baseName.
487 if not self.fileExt.startswith( '.' ) :
488 self.fileExt = self.fileExt + '.'
489
490 self.baseName = self.mainName + self.fileExt
491
492 else : # No fileExt defined - create a reasonable one.
493
494 print >> sys.stderr, '\nERROR: %s::%s: NEITHER baseName NOR mainName Given.' \
495 %( scriptName, defName )
496 sys.exit(1)
497
498 #end if self.baseName [is given]
499
500 self.idName = String2Identifier( self.baseName )
501
502 #end __init__
503
504 #end ImageObject class
505
506 #------------------------------------------------------------------------------
507
508 def ListImageDict( imageDict ) :
509 """
510 Simple DEBUG utiliy to list all an imageDict's attributes
511 except for the image data.
512 """
513 defName = DefName() # For DEBUG
514
515 print '\n---- imageDict :'
516 for imgObj in imageDict.itervalues() :
517 print ' baseName = %s' %( imgObj.baseName )
518 print ' createdExt = %r' %( imgObj.createdExt )
519 print ' mainName = %s' %( imgObj.mainName )
520 print ' idName = %s' %( imgObj.idName )
521 print
522 #end for
523
524 #end def
525
526 #------------------------------------------------------------------------------
527
528 def SortFilenames( fileArgs, enabledMsgs ) :
529 """
530 Sorts a list of filenames into:
531 1) inPyImageFilesList - a list of pyImage files to be input;
532 2) outPyImageFilename - the intended pyImages filename to be written;
533 3) imageFileList - a list of image files to add the the output pyImages file.
534
535 At minimum, one pyImages filename must be given in the args.
536 Checks that all image files exist.
537
538 The last given pyImages file will be the output pyImages file.
539 It doen't have to exist if 1 or more previous existing piImages.py files have been given.
540
541 A lone given pyImages filename will be both input and then overwritten.
542 """
543 defName = DefName() # For DEBUG
544
545
546 allPyImageFilesList = list()
547 imageFileList = list()
548
549 # Sort the filenames in two groups: 1) PyImages files, 2) image files.
550 for filename in fileArgs :
551
552 if filename.lower().endswith( '.py' ) : # A pyImages filename.
553
554 allPyImageFilesList.append( filename )
555
556 else : # Must be an image filename.
557
558 if os.path.exists( filename ) : # Check later if this actually is an image file.
559 imageFileList.append( filename )
560 else :
561 if ('warning' in enabledMsgs) :
562 print 'WARNING: Input Image File DOES NOT EXIST [ %s ]' \
563 %( filename )
564 #end if os.path.exists
565
566 #end if filename.lower().endswith( '.py' )
567
568 #end for filename in fileArgs
569
570 # Create inpPyimgFileList and outPyImageFilename from allPyImageFilesList.
571 numTotalPyImgFiles = len( allPyImageFilesList )
572 if (numTotalPyImgFiles == 0) :
573
574 print >> sys.stderr, 'ERROR: %s::%s: NO GIVEN Output PyImages Filename\n' \
575 %( scriptName, defName )
576 sys.exit(1)
577
578 #-----
579
580 # It's not necessary that this file doesn't yet exist.
581 outPyImageFilename = allPyImageFilesList[ -1 ] # ALWAYS the last filename in the list.
582
583 if numTotalPyImgFiles == 1 :
584
585 # This lone PyImages file will be used for both input and output.
586 # The net effect is to check the validty of its contents.
587 # Additional given image files will be added to its pyImages.
588 # The existance of this file is checked elsewhere.
589 inPyImageFilesList = allPyImageFilesList # The same single-item list
590
591 else : # numTotalPyImgFiles >= 2
592
593 inPyImageFilesList = list()
594 allPyImageFilesList = allPyImageFilesList[ :-1 ] # Check all but the last the given files.
595 for anInpPyImgFile in allPyImageFilesList : # The last is ALWAYS the output file.
596
597 if (not os.path.exists( anInpPyImgFile )) :
598 if ('failure' in enabledMsgs) :
599 msg = 'FAILURE: GIVEN Input PyImages File DOES NOT EXIST [ %s ]' \
600 %( anInpPyImgFile )
601 print msg
602 else :
603 inPyImageFilesList.append( os.path.abspath( anInpPyImgFile ) )
604 #end if
605
606 #end for
607
608 #end if
609
610 if (not imageFileList) :
611 if ('note' in enabledMsgs) :
612 print 'NOTE: NO GIVEN Image Files to Add\n'
613 #end if
614
615 """ DEBUG
616 print '$$$$ inPyImageFilesList'
617 print ' ', inPyImageFilesList
618 print
619 print '$$$$ outPyImageFilename'
620 print ' ', outPyImageFilename
621 print
622 print '$$$$ imageFileList'
623 print ' ', imageFileList
624 print
625 """
626
627 return inPyImageFilesList, outPyImageFilename, imageFileList
628
629 #end SortFilenames def
630
631 #------------------------------------------------------------------------------
632
633 def ImportPyImages( inpPyImgFilename, imageDict, enabledMsgs ) :
634 """
635 Import the pyImages file and add its images to imageDict{}.
636 The file's existance is expected to have been verified.
637 """
638 defName = DefName() # For DEBUG
639
640 pyImgMainName, pyImgExt = os.path.splitext( os.path.basename( inpPyImgFilename ) )
641 pyImportStr = 'from %s import *' %( pyImgMainName )
642
643 try :
644 exec( pyImportStr )
645 except : # Not a fatal error
646 if ('failure' in enabledMsgs) :
647 if os.path.exists( inpPyImgFilename ) :
648 print >> sys.stderr, 'FAILURE: PyImages File Has BAD PYTHON SYNTAX [ %s ]' \
649 %( inpPyImgFilename )
650 #end if
651
652 return imageDict # An empty disctionary.
653
654 #-----
655
656 #end if
657
658 # Check if the Py file is actually a PyImages file.
659 try:
660 catalog.iteritems() # Should have been defined
661
662 except NameError :
663 if ('failure' in enabledMsgs) :
664 msg = 'FAILURE: NOT A PYIMAGES File: [ %s ]' %( inpPyImgFilename )
665 print >> sys.stderr, msg
666 #end if
667
668 return imageDict
669
670 #-----
671
672 #end try
673
674 # Assume, for now, that the key is a baseName and not a mainName.
675 for baseName, catIdName in catalog.iteritems() :
676
677 # Construct the callable function name from the catalog's idName.
678 funcStr = 'GetData_' + catIdName + '()'
679 pngImageData = eval( funcStr )
680
681 # Encode the binary data into viewable 7-bit characters.
682 encPngData = B64EncodeBinaryData( pngImageData )
683
684 # Create an ImageObject for each encoded image and add it to imageDict.
685 # Assume that the baseName from the catalog dict has an extension appended.
686 # ImageObject () will create a nominal extName if none exists in baseName.
687 imgObj = ImageObject( idName=catIdName, baseName=baseName, encPngData=encPngData )
688
689 newIdName = imgObj.idName # Extract the possibley-corrected idName.
690
691 # Check if idName already exists.
692 alreadyInDict = False
693 for anIdName in imageDict.iterkeys() :
694
695 # imageDict keys are the corrected idNames.
696 if (newIdName == anIdName) :
697 alreadyInDict = True
698 break # Search no further - dictionaries can't have duplicate keys.
699 #end if
700
701 #end for
702
703 baseName = imgObj.baseName
704 if alreadyInDict :
705 if ('warning' in enabledMsgs) :
706 print 'WARNING: REDEFINING Image: [ %s ] File: [ %s ]' \
707 %( newIdName, baseName )
708
709 else :
710 if ('note' in enabledMsgs) :
711 print 'NOTE: Reading Image: [ %s ] File: [ %s ]' \
712 %( newIdName, baseName )
713 #end if
714
715 # Use the extension-appended idName for the key,
716 # not the original, possibly extension-less idName read from the pyImages file.
717 imageDict[ imgObj.idName ] = imgObj
718
719 #end for baseName, catIdName in catalog.iteritems()
720
721 return imageDict
722
723 #end ImportPyImages def
724
725 #------------------------------------------------------------------------------
726
727 def WritePyImagesFileHeader( pyImagesFile ) :
728 """
729 Writes Python statements to the output pyImages file.
730 """
731 defName = DefName() # For DEBUG
732
733 pyImagesFile.write( '#' + '-'*69 + '\n\n' )
734 line = '# This file was generated by %s\n\n' %( scriptName )
735 pyImagesFile.write( line )
736 pyImagesFile.write( 'from wx.lib.embeddedimage import PyEmbeddedImage\n' )
737 pyImagesFile.write( '\n' )
738 pyImagesFile.write( 'catalog = {}\n' )
739
740 #end WritePyImagesFileHeader def
741
742 #------------------------------------------------------------------------------
743
744 def WritePyImageDataAndFuncs( imgObj, pyImagesFile, enabledMsgs ) :
745 """
746 Writes the Python code to the output pyImages file that both define an image
747 and to be able to generate raw data, wx.Image, wx.Bitmap and wx.Icon objects
748 when its pyImmages file is imported by any Python application.
749 """
750 defName = DefName() # For DEBUG
751
752 pyImagesFile.write( '#' + '-'*69 + '\n\n' )
753 pyImagesFile.write( '%s = PyEmbeddedImage( \n%s\n' \
754 %( imgObj.idName, imgObj.encPngData) )
755 pyImagesFile.write( ' )\n\n' )
756
757 # When the PyImages file is imported,
758 # the following dictionary idName value will become a function name.
759 pyImagesFile.write( 'catalog["%s"] = "%s"\n' %( imgObj.baseName, imgObj.idName) )
760
761 pyImagesFile.write( 'GetData_%s = %s.GetData\n' %( imgObj.idName, imgObj.idName ) )
762 pyImagesFile.write( 'GetImage_%s = %s.GetImage\n' %( imgObj.idName, imgObj.idName ) )
763 pyImagesFile.write( 'GetBitmap_%s = %s.GetBitmap\n' %( imgObj.idName, imgObj.idName ) )
764 pyImagesFile.write( 'GetIcon_%s = %s.GetIcon\n' %( imgObj.idName, imgObj.idName ) )
765 pyImagesFile.write( '\n' )
766
767 """ DEBUG
768 print '$$$$ Img2PyFile::ImageFileEncodeAndWrite:'
769 print ' '*8 + 'Embedding image as callable identifier [ %s ]' %( imgObj.idName )
770 """
771
772 #end WritePyImagesFileFunctions def
773
774 #------------------------------------------------------------------------------
775
776 def WritePyImageFile( imageDict, outPyImageFilename, enabledMsgs ) :
777 """
778 Writes a new pyImages file from an imageDict.
779 """
780 defName = DefName() # For DEBUG
781
782 if not imageDict :
783 if ('warning' in enabledMsgs) :
784 print 'WARNING: NO IMAGES TO WRITE to PyImages File: [ %s ]' \
785 %( outPyImageFilename )
786 return
787 #end if
788
789 #-----
790
791 if (not os.path.exists( outPyImageFilename )) :
792 if ('progress' in enabledMsgs) :
793 print 'PROGRESS: Writing New PyImages File: [ %s ]' \
794 %( outPyImageFilename )
795
796 else :
797 if ('progress' in enabledMsgs) :
798 print 'PROGRESS: OVERWRITING PyImages File: [ %s ]' \
799 %( outPyImageFilename )
800
801 pyImagesFile = open( outPyImageFilename, 'w' ) # Delete any existing file.
802
803 # Write the header once,
804 WritePyImagesFileHeader( pyImagesFile )
805
806 # For each imgObject write its encoded data and functions.
807 for imgObj in imageDict.itervalues() :
808 WritePyImageDataAndFuncs( imgObj, pyImagesFile, enabledMsgs )
809
810 pyImagesFile.close()
811
812 #end WritePyImageFile def
813
814 #------------------------------------------------------------------------------
815
816 class Img2PyFile() :
817 """
818 The main class to instantiate. See the __doc__ string for all details.
819 """
820
821 def __init__( self, args=None ) :
822 defName = 'Img2PyFile()'
823
824 enabledMsgs, fileArgs = ProcessArgs( args )
825
826 inPyImageFilesList, outPyImageFilename, imageFileList = SortFilenames( fileArgs, enabledMsgs )
827
828 if not wx.GetApp() : # Has the user's program already created a wx.App ?
829 app = wx.App( redirect=False ) # No, create a dummy app to enable accessinng all wx's methods.
830
831 #-----
832
833 # Import any existing PyImages files and populate imageDict from them.
834 # There must be at least one pyImages file.
835 imageDict = dict() # Brand new, empty
836 for anInpPyImgFile in inPyImageFilesList :
837
838 if (os.path.exists( anInpPyImgFile ) and ('progress' in enabledMsgs)) :
839 print 'PROGRESS: Reading Existing PyImages File: [ %s ]' \
840 %( anInpPyImgFile )
841
842 # Add to imageDict{} given the current content of imageDict{}.
843 imageDict = ImportPyImages( anInpPyImgFile, imageDict, enabledMsgs )
844
845 #ListImageDict( imageDict ) # DEBUG
846
847 #end for
848
849 #-----
850
851 if imageFileList : # Might be "None".
852
853 if ('progress' in enabledMsgs) :
854 print 'PROGRESS: Reading New Image Files:'
855
856 # Add the new images to imageDict
857 for imgFilename in imageFileList :
858
859 # Convert the filename to a legal Python identifier string.
860 baseName = os.path.basename( imgFilename )
861 mainName, fileExt = os.path.splitext( baseName )
862 idName = String2Identifier( baseName )
863
864 # Check if the image name already exists imageDict.
865 overWriting = False
866 for imgObj in imageDict.values() :
867
868 if (idName == imgObj.idName) :
869 overWriting = True
870 break
871 #end for
872
873 # Convert image to PNG file data format.
874 # Result may be None if an error occurs.
875 pngImageData = CreatePngFileData( imgFilename, enabledMsgs )
876 if pngImageData :
877
878 # Any errors
879 encPngData = B64EncodeBinaryData( pngImageData )
880
881 # Create a new ImageObject and populate it.
882 imgObj = ImageObject( idName, baseName, mainName, fileExt, encPngData )
883
884 # Add it to the image dictionary.
885 imageDict[ idName ] = imgObj
886
887 if overWriting :
888 if ('warning' in enabledMsgs) :
889 print 'WARNING: OVERWITING Image: [ %s ] File: [ %s ]' \
890 %( idName, baseName )
891 else :
892 if ('action' in enabledMsgs) :
893 print 'ACTION: Adding Image: [ %s ] File: [ %s ]' \
894 %( idName, baseName )
895 #end if overWriting
896
897 #end if pngImageData
898 #end for imgFilename in imageFileList
899 #end if imageFileList
900
901 """ DEBUG
902 ListImageDict( imageDict )
903 """
904
905 #-----
906
907 # Write a new PiImages.py file.
908 WritePyImageFile( imageDict, outPyImageFilename, enabledMsgs )
909
910 #end __init__
911
912 #end Img2PyFile class
913
914 #==============================================================================
915
916 if __name__ == '__main__' :
917
918 #WhatsInstalled() # Platform information
919
920 cmdLineArgs = sys.argv[ 1: ]
921 Img2PyFile( cmdLineArgs )
922
923 #end if
Attached Files
To refer to attachments on a page, use attachment:filename, as shown below in the list of files. Do NOT use the URL of the [get] link, since this is subject to change and can break easily.You are not allowed to attach a file to this page.