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.
  • [get | view] (2012-05-04 19:57:15, 33.3 KB) [[attachment:EditorPanel_Demo.png]]
  • [get | view] (2012-05-04 19:57:22, 26.8 KB) [[attachment:EditorPanel_Demo.py]]
  • [get | view] (2011-05-26 18:16:27, 2.6 KB) [[attachment:EmbeddedGraphicData.py]]
  • [get | view] (2011-05-26 06:11:57, 2.9 KB) [[attachment:Hand.png]]
  • [get | view] (2012-04-30 18:47:53, 38.0 KB) [[attachment:Image2PyFile.PY]]
  • [get | view] (2012-04-26 21:18:00, 31.9 KB) [[attachment:Image2PyFile.py]]
  • [get | view] (2012-04-30 18:36:42, 7.1 KB) [[attachment:Image2PyFile_GUI.py]]
  • [get | view] (2012-04-27 03:22:42, 20.5 KB) [[attachment:Image2PyFile_GUI_Output.png]]
  • [get | view] (2011-05-26 06:41:02, 42.1 KB) [[attachment:Image2PyFile_GUI_Output_Again.png]]
  • [get | view] (2012-04-26 23:27:42, 26.8 KB) [[attachment:Image2PyFile_Output.png]]
  • [get | view] (2011-05-26 06:12:55, 2.9 KB) [[attachment:Minus.png]]
  • [get | view] (2011-05-26 06:13:18, 2.9 KB) [[attachment:Plus.png]]
  • [get | view] (2011-05-26 18:13:55, 2.8 KB) [[attachment:Separator.png]]
  • [get | view] (2012-05-04 19:44:48, 19.8 KB) [[attachment:wxToolBar_Embedded_Demo.png]]
  • [get | view] (2012-05-04 19:45:04, 11.2 KB) [[attachment:wxToolBar_Embedded_Demo.py]]
 All files | Selected Files: delete move to page copy to page

You are not allowed to attach a file to this page.

NOTE: To edit pages in this wiki you must be a member of the TrustedEditorsGroup.