If you benefit from web2py hope you feel encouraged to pay it forward by contributing back to society in whatever form you choose!

Model:

db.define_table('uploads',
    Field('name','string'),
    Field('mainfile','upload'),
    Field('thumb','upload',writable=False,readable=False),
    )

Controller:

def makeThumbnail(dbtable,ImageID,size=(150,150)):
    try:    
        thisImage=db(dbtable.id==ImageID).select()[0]
        import os, uuid
        from PIL import Image
    except: return
    im=Image.open(request.folder + 'uploads/' + thisImage.mainfile)
    im.thumbnail(size,Image.ANTIALIAS)
    thumbName='uploads.thumb.%s.jpg' % (uuid.uuid4())
    im.save(request.folder + 'uploads/' + thumbName,'jpeg')
    thisImage.update_record(thumb=thumbName)
    return 

def uploadimage():
    dbtable = db.uploads          #uploads table name
    if len(request.args):
        records = db(dbtable.id==request.args[0]).select()
    if len(request.args) and len(records):
        form = SQLFORM(dbtable, records[0], deletable=True)
    else:
        form = SQLFORM(dbtable)
    if form.accepts(request.vars, session): 
        response.flash = 'form accepted'
        makeThumbnail(dbtable,form.vars.id,(175,175))
    elif form.errors:
        response.flash = 'form has errors'
    ## Quick list just to demonstrate...
    list = crud.select(dbtable)
    return dict(form=form,list=list)

(I am grateful to Lukasz (aka ls1) for his kind assistance).

Related slices

Comments (11)

  • Login to post



  • 0
    sherdim 14 years ago
    This solution supposes initial keeping of the uploaded BIG image. I am not a specialist in the webserver memory utilization, but a solution with validator RESIZE, which called on any upload to the given field is more straightforward IMHO. Such solution was published in the web2py group about a year ago. It utilizes PIL also and cStringIO as a temporal buffer. The same approach was for automarking images with the site logo. Place a module with validator in module folder. ================ __all__ = [ 'RESIZE', ] class RESIZE(object): """ Resize image such as thumbnail """ def __init__(self,nx=160,ny=80,error_message='image resize error'): (self.nx,self.ny,self.error_message)=(nx,ny,error_message) def __call__(self,value): if isinstance(value, str) and len(value)==0: return (value,None) from PIL import Image import cStringIO try: #load im=Image.open(value.file) #resize im.thumbnail((self.nx,self.ny),Image.ANTIALIAS) #by hand s=cStringIO.StringIO() im.save(s,'JPEG',quality=86) s.seek(0) value.file=s except: return (value,self.error_message) else: return (value,None) =========== Vale!

  • 0
    villas 14 years ago
    The validator is good for transforming a field, but at the end you just have one image/field. In the case of this slice I wanted to automatically create a thumbnail from an upload which would result in having two files/fields. I think the use case is therefore different. However, it is still good to know this RESIZE validator. Thanks.

  • 0
    rppowell 14 years ago
    just wanted to add that the thumbnail image name matters (at least in the current version of web2py). I ended up with this code:
    
    def makeThumbnail(img_name,size=(150,150)):
        try:    
            import os
            from PIL import Image
        except: 
            return
        im=Image.open(request.folder + 'uploads/' + img_name)
        im.thumbnail(size,Image.ANTIALIAS)
        root,ext = os.path.splitext(img_name)
        thumbName='%s_thumb%s' %(root, ext)
        im.save(request.folder + 'uploads/' + thumbName)
        return thumbName
    
    def add():
        form = SQLFORM(db.Item)
        if form.accepts(request.vars, session):
            response.flash = "Item Added"
            row = db(db.Item.id==form.vars.id).select()[0]
            img_name=row.image
            thumb = makeThumbnail(img_name)
            if thumb: row.update_record(image_thumb=thumb)
        elif form.errors:
            response.flash = "Form has errors"
        return dict(form=form)
    
    Does the thumbnail really need a UUID that is not related to the original image?

  • 0
    rppowell 14 years ago
    I guess I should put back in the original error checking!

  • 0
    simpel 14 years ago
    You can do also:
    
    
    class RESIZE(object): 
        def __init__(self,nx=160,ny=80,error_message='niepoprawny plik'): 
            (self.nx,self.ny,self.error_message)=(nx,ny,error_message) 
        def __call__(self,value):
            if isinstance(value, str) and len(value)==0: 
                return (value,None) 
            from PIL import Image 
            import cStringIO 
            try: 
                img = Image.open(value.file) 
                img.thumbnail((self.nx,self.ny), Image.ANTIALIAS) 
                s = cStringIO.StringIO() 
                img.save(s, 'JPEG', quality=100) 
                s.seek(0) 
                value.file = s 
            except: 
                return (value, self.error_message) 
            else: 
                return (value, None)
                
    def THUMB(image, nx=120, ny=120):
        from PIL import Image 
        import os  
        img = Image.open(request.folder + 'uploads/' + image)
        img.thumbnail((nx,ny), Image.ANTIALIAS) 
        root,ext = os.path.splitext(image)
        thumb='%s_thumb%s' %(root, ext)
        img.save(request.folder + 'uploads/' + thumb)
        return thumb
    
    
    db.define_table('gallery',
        Field('image', 'upload', required=True, notnull=True, requires=[IS_IMAGE(), RESIZE(650, 650)]),
        Field('image_thumb', 'upload', compute=lambda r: THUMB(r['image'])))
    
    
    
    Why can't I edit my own comment? Can somebody delete my first comment? Thanks
show more comments

Hosting graciously provided by:
Python Anywhere