fvrghl
fvrghl

Reputation: 3728

How to Display Image with web.py

I am trying to let a user upload an image, save the image to disk, and then have it display on a webpage, but I can't get the image to display properly. Here is my bin/app.py:

import web                                                                         

urls = (                                                                           
        '/hello', 'index'                                                          
        )                                                                          

app = web.application(urls, globals())                                             

render = web.template.render('templates/', base="layout")                          

class index:                                                                       
    def GET(self):                                                                 
        return render.hello_form()                                                 

    def POST(self):                                                                
        form = web.input(greet="Hello", name="Nobody", datafile={})                
        greeting = "%s, %s" % (form.greet, form.name)                                                                
        filedir = 'absolute/path/to/directory'
        filename = None                                                            
        if form.datafile:                                                     
            # replaces the windows-style slashes with linux ones.                  
            filepath = form.datafile.filename.replace('\\','/')                    
            # splits the and chooses the last part (the filename with extension)
            filename = filepath.split('/')[-1]                                     
            # creates the file where the uploaded file should be stored            
            fout = open(filedir +'/'+ filename,'w')                                
            # writes the uploaded file to the newly created file.                  
            fout.write(form.datafile.file.read())                                  
            # closes the file, upload complete.                                    
            fout.close()                                                           
            filename = filedir + "/" + filename                                    
        return render.index(greeting, filename)                                    

if __name__ == "__main__":                                                         
    app.run()     

and here is templates/index.html:

$def with (greeting, datafile)                                                     

$if greeting:                                                                      
    I just wanted to say <em style="color: green; font-size: 2em;">$greeting</em>
$else:                                                                             
    <em>Hello</em>, world!                                                         
<br>                                                                               
$if datafile:                                                                      
    <img src=$datafile alt="your picture">                                         
<br>                                                                               
<a href="/hello">Go Back</a>  

When I do this, I get a broken link for the image. How do I get the image to display properly? Ideally, I wouldn't have to read from disk to display it, although I'm not sure if that's possible. Also, is there a way to write the file to the relative path, instead of the absolute path?

Upvotes: 2

Views: 3727

Answers (2)

JRogerC
JRogerC

Reputation: 678

You can also insert a path to all images in a folder by adding an entry to your URL.

URL = ('/hello','Index',
       '/hello/image/(.*)','ImageDisplay'
      )
...
class ImageDisplay(object):
   def GET(self,fileName):
      imageBinary = open("/relative/path/from/YourApp}"+fileName,'rb').read()
      return imageBinary

Not the ../YourApp, not ./YourApp. It looks up one directory from where your prgram is. Now, in the html, you can use

<img src="/image/"+$datafile alt="your picture">

I would recommend using with or try with the "imageBinary = open("{..." line.

Let me know if more info is needed. This is my first response.

Sorry to ask a question in a responce, but is there a way to use a regular expression, like (.jpg) in place of the (.) I have in the URL definition?

Upvotes: 1

icktoofay
icktoofay

Reputation: 129139

web.py doesn't automatically serve all of the files from the directory your application is running in — if it did, anyone could be able to read your application's source code. It does, however, have a directory it serves files out of: static.

To answer your other question: yes, there is a way to avoid using an absolute path: give it a relative path!

Here's how your code might look afterwards:

filename = form.datafile.filename.replace('\\', '/').split('/')[-1]
# It might be a good idea to sanitize filename further.

# A with statement ensures that the file will be closed even if an exception is
# thrown.
with open(os.path.join('static', filename), 'wb') as f:
    # shutil.copyfileobj copies the file in chunks, so it will still work if the
    # file is too large to fit into memory
    shutil.copyfileobj(form.datafile.file, f)

Do omit the filename = filedir + "/" + filename line. Your template need not include the absolute path: in fact, it should not; you must include static/; no more, no less:

<img src="static/$datafile" alt="your picture">

Upvotes: 0

Related Questions