
import os
import wx
import Image        # Pil properly reads all files with alpha transparency.
import ImgConv      # Interonvert Pil images, wxImages and wxBitmaps.

#------------------------------------------------------------------------------

def GetWxImageFromFile( imgFilename ):
    
    # Read all image files using Pil.
    # Wx incorrectly reads alpha from PNG files.
    #wxImage = wx.Image( filename, wx.BITMAP_TYPE_ANY )
    
    pilImage = Image.open( imgFilename )
    
    # Convert to a wxImage while preseving any alpha transparency.
    wxImage = ImgConv.WxImageFromPilImage( pilImage )
    
    return wxImage
    
#end def

#------------------------------------------------------------------------------

def GetImageFilesListFromFolder( folder, debug=True ):
    
    imageFileExts = [ '.bmp', '.gif', '.png', '.jpg', '.jpeg', '.ico', '.pnm', '.pcx', '.tif' ]
    
    allFilenames = []
    if os.path.exists( folder ) :    allFilenames = os.listdir( folder )
    
    imageFilesList = []
    for aFilename in allFilenames:
        
        aFileBasename, aFileBasenameExt = os.path.splitext( aFilename )
        
        if aFileBasenameExt.lower() in imageFileExts:
            imageFilesList.append( os.path.abspath( folder + '/' + aFilename ) )
        
    #end for

    if len( imageFilesList ) == 0:    imageFilesList = [ '' ]    # avoid any index errors
    
    return imageFilesList

#end def

#------------------------------------------------------------------------------

class ImageWindow( wx.Window ):

    def __init__( self, parent, id=-1, filePath='/', pos=(0, 0), size=(0, 0) ):   # Dummy pos and size

        wx.Window.__init__( self, parent, id, pos=pos, size=size )  # Frame has no decorations.
        
        self.parent=parent

        self.backgroundColor    = (230, 230, 250)       # light blue
        self.backgroundColor    = 'PURPLE'
        self.borderColor        = (0, 120, 0)
        
        self.imageFilesList = GetImageFilesListFromFolder( filePath )
        self.imageFileIsListIndex = 0     # running list index
        
        self.Bind( wx.EVT_PAINT, self.OnPaint )

    #end def __init__
    
    #----------------------------------------------------------------

    def OnPaint( self, event ):  # invoked when window is first created.
        
        dc = wx.PaintDC( self )     # Must be created on every OnPaint event.
        self.DrawImage( dc )
        
        event.Skip()    # Very important to let all higher level handlers be called.
        
    #end def
    
    #----------------------------------------------------------------
    
    def OnDisplayNextImageFile( self, event ):
        
        if os.path.exists( self.imageFilesList[ self.imageFileIsListIndex ] ):
            
            ##print self.imageFilesList[ self.imageFileIsListIndex ]    # DEBUG
            
            # Create a wxImage from a file and display it in the image frame.
            self.wxImage = GetWxImageFromFile( self.imageFilesList[ self.imageFileIsListIndex ] )
            self.parent.Refresh()          # invokes OnPaint
            
        else:
            print '####   No Image Files in Subdirectory "IMAGES".'
            return
        #end if
        
        self.imageFileIsListIndex += 1
        if ( self.imageFileIsListIndex == len( self.imageFilesList ) ):    
             self.imageFileIsListIndex = 0
        
    #end def
    
    #----------------------------------------------------------------
    
    def PaintImageWindowClientBackground( self, dc, clientSize ):
    
        brush = wx.Brush( wx.NamedColour(self.backgroundColor ), wx.SOLID )
        dc.SetBrush( brush )
        borderWidth = 10
        dc.SetPen( wx.Pen( self.borderColor, borderWidth ) )
        clientOffsetX = clientOffsetY = 0
        dc.DrawRectangle( clientOffsetX, clientOffsetY , clientSize[0], clientSize[1] )
        
    #end def
        
    #----------------------------------------------------------------
    
    def DrawImage( self, dc ) :
        
        clientSize = self.GetClientSize()
        clientSizeX, clientSizeY = clientSize
        
        self.PaintImageWindowClientBackground( dc, clientSize )      # Be able to see client area.
        
        try:
            self.wxImage    # Been created yet ?
        except:
            return          # No.
        #end try
        
        #--------------------
        
        wxImageX, wxImageY = self.wxImage.GetSize()     # Fixed.
        imageAspect = float( wxImageX ) / float( wxImageY )
        
        clientAspect = float( clientSizeX ) / float( clientSizeY )
        
        margin = 10     # arbitrary minimum padding width.
        
        maxWid = clientSizeX - margin                   # Fixed.
        maxHgt = clientSizeY - margin
        
        # Resize the image proportionally so that it just fits into the frame-margins.
        if   (imageAspect > clientAspect) :
            
            adjWid = maxWid
            adjHgt = int( maxWid / imageAspect )
            
        else :
            
            adjWid = int( maxHgt * imageAspect )
            adjHgt = maxHgt
            
        #end if
        
        offX = (margin + maxWid - adjWid ) / 2
        offY = (margin + maxHgt - adjHgt ) / 2
        
        if (adjWid > 0) and (adjHgt > 0) :          # DEBUG
        
            self.wxImage.Rescale( adjWid, adjHgt )    # rescale to fit within the DC's margins
        
            wxBmap = self.wxImage.ConvertToBitmap()
        
            dc.DrawBitmap( wxBmap, offX, offY )     # draw the bitmap on the frame client
            
        #end if
        
    #end def DrawImage

#end class ImageWindow

#------------------------------------------------------------------------------

class AppFrame( wx.Frame ):

    def __init__( self, parent, id, title, filePath='./', 
                        pos=wx.DefaultPosition, size=wx.DefaultSize ):    # dummies
        
        wx.Frame.__init__( self, parent, id, title, pos=pos, size=size )
        
        self.SetBackgroundColour( 'WHITE' )

        self.SetSize( (400, 400) )
        self.SetPosition ( (100, 50) )
        
        # Create a display sub-window that will hold the image DC.
        self.imageFrame = ImageWindow( self, id=-1, size=(200, 250), filePath=filePath )
        
        #-----
        
        btn = wx.Button( self, -1, 'Display Next Image File' )
        wx.EVT_BUTTON( self, btn.GetId(), self.imageFrame.OnDisplayNextImageFile )
        
        #-----
        
        self.sizer = wx.BoxSizer( wx.VERTICAL )
        self.sizer.Add( (30, 30)  )
        self.sizer.Add( btn, 0, wx.CENTER, 10 )    # 10-pixel border all around button
        
        self.sizer.Add( (30, 30)  )
        self.sizer.Add( self.imageFrame, 0, wx.CENTER )
        
        self.sizer.Fit( self )
        self.SetAutoLayout( True )
        self.SetSizer( self.sizer )
                
        self.imageFrame.OnDisplayNextImageFile( None )
        
        #-----

        wx.EVT_CLOSE( self, self.OnCloseWindow )
        
        #-----

    #end def __init__

    #------------------------
    
    def OnCloseWindow( self, event ):    self.Destroy()

#end class AppFrame

#----------------------------------------------------------------------------------------

if __name__ == '__main__':

    myApp = wx.App( False )   # Send errors to command window, not a pop-up.
    myFrame = AppFrame( None, -1, 'Display wxImages From Files', filePath='IMAGES' )
    myApp.SetTopWindow( myFrame )
    myFrame.Show()
    myApp.MainLoop()

#end if
