[AG-TECH] Updated image viewer

Dave Semeraro semeraro at ncsa.uiuc.edu
Fri Nov 14 12:46:33 CST 2003


Hi Techers,

I have attached a new version of the image viewer program. The improved 
version is compatible
with AG2.1 and the new way to register applications with the venue client. 
In addition the
application stores the image in the venue data area instead of the 
application object. Thanks
to Tom Uram for making these changes for me. I added the drag and drop 
capability and fixed
a bug that would cause a previous image to persist when a smaller image was 
loaded. Both of
these things are simple fixes. Still to do is add the markup capability and 
scrolled window
capability. Hey, I still have a couple of more days before SC :).

The new code has been verified under windows and Linux. To register the 
shared application
save the attachments ( AGBasicImage.py and AGBasicImage.app) somewhere and 
run the
package manager tool from the same directory like this:

c:\directorywithappfile> agpm.py -f AGBasicImage.app

That should do the trick. After that just fire up the venueclient, add the 
BasicImage application,
drag an image file to it and enjoy.. I hope.

Anyway that is about it. I hope you find this version useful.

Regards,
Dave


Dave Semeraro Ph.D.
Visualization and Virtual Environments Group
NCSA University of Illinois
605 E. Springfield Ave.
Champaign, IL 61820
Semeraro at ncsa.uiuc.edu
(217) 244-1852
-------------- next part --------------
"""
This is the Access Grid Enabled version of the Basic Image viewer. It does the same
thing as the Basic Image ( load an image into a window ) but will share the image over
the Access Grid. Again there is no way to pan or scroll the window. This is just an
attempt to get the BasicImage viewer to work over the AG. The scheme is that the script is executed 
and given an application URL... like this AGBasicImage appurl. There is no error handling in
this version.

Dave Semeraro
NCSA-UIUC
2003
"""

"""
Modifications:
-   Change state from image data stored in the appobject to the name of a 
    venue-resident image file
-   If a local file is opened, it is transferred to the venue
"""

# generic and gui related imports
import os
import sys
from wxPython.wx import *
import base64
import cPickle
import string

# AG related imports
import logging
from AccessGrid.hosting.pyGlobus import Client
from AccessGrid import Events
from AccessGrid import EventClient
from AccessGrid import Platform
from AccessGrid.DataStoreClient import GetVenueDataStore


ID_OPEN = wxNewId()
ID_OPEN_VENUE = wxNewId()
ID_EXIT = wxNewId()

wildcard = "JPEG Files (*.JPG)|*.jpg|"\
           "Gif Files (*.GIF)|*.gif|"\
           "All Files (*.*)|*.*"
class BIFileDropTarget(wxFileDropTarget):
        def __init__(self,window):
                wxFileDropTarget.__init__(self)
                self.window = window
        def OnDropFiles(self,x,y,filenames):
                for file in filenames:
                        self.window.wind.LoadImageFromFilename(file)
                        # load up the dropped file into venue
                        self.window.AG.UploadFile(file)
                        self.window.AG.PutData(self.window.imagedataname,os.path.split(file)[1])
                        # fire event telling all there is new data
                        self.window.AG.SendEvent("NewImage",os.path.split(file)[1])

# this is an image holder object.. guess what it does. 
class ImageHolder:
    def __init__(self,image,name):
        self.imagename = name
        self.width = str(image.GetWidth())
        self.height = str(image.GetHeight())
        self.data = base64.encodestring(image.GetData())

# A helper class to hide all the AG ugly 
class AGSharedObject:
    def __init__(self,url,venueUrl):
        self.logname = "AGBasicImagelog"
        self.appUrl = None
        self.appName        = "Basic Image"
        self.appDescription = "Access Grid Shared Image"
        self.appMimetype    = "application/x-ag-basic-image"
        self.init_logging(self.logname)

        self.log.debug("AGSharedObject: initialize with url = %s ", url)
        self.appUrl = url
        self.log.debug("AGSharedObject: Getting application proxy")
        self.appProxy = Client.Handle(self.appUrl).GetProxy()
        self.log.debug("AGSharedObject: join application")
        (self.puid,self.prid) = self.appProxy.Join()
        self.log.debug("AGSharedObject: get data channel")
        (self.chanid,self.esl) = self.appProxy.GetDataChannel(self.prid)
        self.eventClient = EventClient.EventClient(self.prid,self.esl,self.chanid)
        self.eventClient.Start()
        self.eventClient.Send(Events.ConnectEvent(self.chanid,self.prid))
        self.log.debug("AGSharedObject: connected and event channel started")
        
        self.dataStoreClient = GetVenueDataStore(venueUrl)

    def init_logging(self,logname):
        logFormat = "%(name)-17s %(asctime)s %(levelname)-5s %(message)s"
        self.log = logging.getLogger(logname)
        self.log.setLevel(logging.DEBUG)
        self.log.addHandler(logging.StreamHandler())

    def GetData(self,dataname):
        self.log.debug("looking for data: %s", dataname)
        tim = self.appProxy.GetData(self.prid,dataname)
        if len(tim) > 0:
            return tim
        else:
            return None

    def PutData(self,dataname,data):
        self.log.debug("loading data named: %s into server",dataname)
        self.appProxy.SetData(self.prid,dataname,data)

    def RegisterEvent(self,eventname,callback):
        self.log.debug("Registering event %s :",eventname)
        self.eventClient.RegisterCallback(eventname,callback)

    def SendEvent(self,eventname,eventdata):
        self.eventClient.Send(Events.Event(eventname,self.chanid,(self.puid,eventdata)))
        
    def UploadFile(self,localFile):

        # Upload the file
        self.dataStoreClient.Upload(localFile)
        
        # Construct the venue data url
        file = os.path.split(localFile)[-1]
        venueDataUrl = os.path.join(self.dataStoreClient.uploadURL, file)
        
        return venueDataUrl
        
    def DownloadFile(self,venueDataUrl):
        # Construct the local filename
        file = os.path.split(venueDataUrl)[-1]
        path = os.path.join(Platform.GetTempDir(),file)
        
        # Update the local store of venue data
        self.dataStoreClient.LoadData()
        
        # Download the file
        self.dataStoreClient.Download(venueDataUrl,file)
        
        return file

class ImageWindow(wxWindow):
    def __init__(self,parent,ID):
        wxWindow.__init__(self,parent,ID,style=wxNO_FULL_REPAINT_ON_RESIZE)
        self.imagefile = None
        self.image = None
        self.SetBackgroundColour("WHITE")
        self.InitBuffer()
        EVT_IDLE(self,self.OnIdle)
        EVT_SIZE(self,self.OnSize)
        EVT_PAINT(self,self.OnPaint)
        
    def InitBuffer(self):
        size = self.GetClientSize()
        if self.image == None:
            self.buffer = wxEmptyBitmap(size.width,size.height)
            dc = wxBufferedDC(None,self.buffer)
            dc.SetBackground(wxBrush(self.GetBackgroundColour()))
            dc.Clear()
        else:
            self.Clear()
            self.buffer = self.image.ConvertToBitmap()
            dc = wxBufferedDC(None,self.buffer)
            dc.SetBackground(wxBrush(self.GetBackgroundColour()))
        self.reInitBuffer = false

    def LoadImageFromFilename(self,imagefilename):
        self.imagefile = imagefilename
        self.image = wxImage(self.imagefile)
        self.reInitBuffer = true
        self.Refresh(true)

    def LoadImage(self,animage):
        imgdat = base64.decodestring(animage.data)
        self.image = wxEmptyImage(string.atoi(animage.width),string.atoi(animage.height))
        self.image.SetData(imgdat)
        self.reInitBuffer = true

    def OnIdle(self,event):
        if self.reInitBuffer:
            self.InitBuffer()
            self.Refresh(FALSE)

    def OnSize(self,event):
        self.reInitBuffer = true

    def OnPaint(self,event):
        dc = wxBufferedPaintDC(self,self.buffer)
        
class ImageFrame(wxFrame):
    def __init__(self,parent,ID):
        wxFrame.__init__(self,parent,ID,"AGImage: no image loaded",size=(800,600),
                         style=wxDEFAULT_FRAME_STYLE | wxNO_FULL_REPAINT_ON_RESIZE)
        menu = wxMenu()
        menu.Append(ID_OPEN,"&Open...","Open an image file")
        menu.Append(ID_OPEN_VENUE,"&Open from venue...","Open a venue image file")
        menu.AppendSeparator()
        menu.Append(ID_EXIT,"&Exit","Terminate with extreme prejudice")
        menubar = wxMenuBar()
        menubar.Append(menu,"&File")
        self.SetMenuBar(menubar)

        EVT_MENU(self,ID_OPEN, self.On_Open)
        EVT_MENU(self,ID_OPEN_VENUE, self.On_OpenVenue)
        EVT_MENU(self,ID_EXIT, self.On_Exit)

        # start the ag stuff and see if there is an image already there
        self.imagedataname = "ImageFile"
        self.wind = ImageWindow(self,-1)
        dt=BIFileDropTarget(self)
        self.SetDropTarget(dt)
        self.AG = AGSharedObject(sys.argv[1], sys.argv[2])
        self.AG.RegisterEvent("NewImage",self.HandleNewImage)
        animage = self.AG.GetData(self.imagedataname)
        if animage == None:
            print "No image found in server"
        else:
            print "Loading image: ", animage
            localImageFile = self.AG.DownloadFile(animage)
            self.LoadImageFromFilename(localImageFile)

    def On_Open(self,event):
        dlg = wxFileDialog(self,"Select An Image", os.getcwd(), "",wildcard,wxOPEN)
        if dlg.ShowModal() == wxID_OK:
        
            # Load the image locally
            localImageFile = dlg.GetPath()
            
            # Push the data to the venue server
            # - copy the image to the venue server
            venueImageFile = self.AG.UploadFile(localImageFile)
            file = os.path.split(localImageFile)[-1]
            
            # - store the image url in the app object
            self.AG.PutData(self.imagedataname, file)
            
            # Load the image locally
            self.LoadImageFromFilename(localImageFile)

            # Now fire the event that tells everyone else the image is changed
            self.AG.SendEvent("NewImage",file)

    def On_OpenVenue(self,event):
    
        self.AG.dataStoreClient.LoadData()
    
        # Let user select a venue file
        dlg = wxSingleChoiceDialog( self, "Select an image file to load", "Load Venue Image Dialog", 
                                    self.AG.dataStoreClient.dataIndex.keys() )


        if dlg.ShowModal() == wxID_OK:
        
            venueImageFile = dlg.GetStringSelection()

            # Download the file locally
            localImageFile = self.AG.DownloadFile(venueImageFile)
            
            # Store the image url in the app object
            self.AG.PutData(self.imagedataname, venueImageFile)
            
            # Now fire the event that tells everyone else the image is changed
            file = os.path.split(localImageFile)[-1]
            self.AG.SendEvent("NewImage",file)

            # Load it
            self.LoadImageFromFilename(localImageFile)
        
    def HandleNewImage(self,eventdata):
        # received notification that there is a new image on the server
        (senderId,venueImageFile) = eventdata.data
        
        if senderId != self.AG.puid:
          try:
            # Download the file locally
            localImageFile = self.AG.DownloadFile(venueImageFile)
            
            # Load the image
            self.LoadImageFromFilename(localImageFile)
            
          except:
            print "EXCEPTION : ", sys.exc_type, sys.exc_value
            import traceback
            traceback.print_stack()
            
    def LoadImageFromFilename(self,filename):
        # Load the image
        self.wind.LoadImageFromFilename(filename)
        
        # Set the window title
        title = os.path.split(filename)[-1]
        self.SetTitle(title)

    def On_Exit(self,event):
        self.Close(true)

class MyApp(wxApp):
    def OnInit(self):
        wxInitAllImageHandlers()
        frame = ImageFrame(None,-1)
        frame.Show(true)
        self.SetTopWindow(frame)
        return true

app = MyApp(0)
app.MainLoop()
-------------- next part --------------
A non-text attachment was scrubbed...
Name: AGBasicImage.app
Type: application/octet-stream
Size: 189 bytes
Desc: not available
URL: <http://lists.mcs.anl.gov/pipermail/ag-tech/attachments/20031114/e9f721ad/attachment.obj>


More information about the ag-tech mailing list