Created
October 12, 2012 14:39
-
-
Save jperler/3879523 to your computer and use it in GitHub Desktop.
PIL Wrapper
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import socket | |
import urllib2, uuid, os | |
from PIL import Image, ImageChops, ImageOps | |
import simplejson as json | |
from settings import MEDIA_ROOT | |
from studio.misc import PhotoSize | |
""" | |
Dependencies: PIL | |
Settings: MEDIA_ROOT (directory where files are stored) | |
Following class is used in the class usage examples: | |
class PhotoSize: | |
Timeline=(940, 375) | |
Thumbnail=(195, 146) | |
CoverThumbnail = (275, 125) | |
Thumbnail84x84 = (84, 84) | |
Logo = (60, 60) | |
""" | |
class BaseImageProcessor: | |
""" | |
utility to resize images | |
""" | |
def __init__(self, base_dir, **kwargs): | |
self.base_dir = base_dir | |
self.id = uuid.uuid1() | |
self.quality = 90 | |
self.extension = None | |
self.success = True | |
def save(self): | |
pass | |
def get_original(self): | |
return '%s.%s' % (self.id, self.extension) | |
def get_filename(self): | |
return '%s/%s.%s' % (self.base_dir, self.id, self.extension) | |
def get_extension(self, filename): | |
return filename.split('/')[-1:][0].split('.')[-1:][0] | |
def clean_up(self): | |
os.remove(self.get_filename()) | |
def rescale(self, dimension, force=False): | |
nw = dimension[0] | |
nh = dimension[1] | |
padding = False | |
try: | |
img = Image.open(self.get_filename()) | |
pw, ph = img.size | |
pr = float(pw) / float(ph) | |
nr = float(nw) / float(nh) | |
if force: | |
# this is mainly used for logos or images that shouldn't be cropped | |
img.thumbnail((nw, nh), Image.ANTIALIAS) | |
elif pr >= nr: | |
# photo aspect is wider than destination ratio | |
tw = int(round(nh * pr)) | |
if pw < tw: | |
padding = True | |
else: | |
# reduce width | |
img = img.resize((tw, nh), Image.ANTIALIAS) | |
l = int(round(( tw - nw ) / 2.0)) | |
img = img.crop((l, 0, l + nw, nh)) | |
elif pr < nr: | |
# photo aspect is taller than destination ratio | |
th = int(round(nw / pr)) | |
if ph < th: | |
padding = True | |
else: | |
# reduce height | |
img = img.resize((nw, th), Image.ANTIALIAS) | |
t = int(round(( th - nh ) / 2.0)) | |
img = img.crop((0, t, nw, t + nh)) | |
if padding: | |
# add black padding instead of stretching | |
img = img.crop( (0, 0, nw, nh) ) | |
offset_x = max(int(round(( nw - pw ) / 2.0)), 0) | |
offset_y = max(int(round(( nh - ph ) / 2.0)), 0) | |
img = ImageChops.offset(img, offset_x, offset_y) | |
filename = '%s_%s_%s.%s' % ( | |
self.id, | |
nw, | |
nh, | |
self.extension | |
) | |
img.save('%s/%s' % (self.base_dir, filename), 'JPEG', quality = self.quality) | |
return filename | |
except IOError: | |
self.success = False | |
def is_success(self): | |
return self.success | |
def get_json_response(self): | |
result = {'success': self.is_success(), | |
'original': self.get_original(), | |
'id': '%s' % self.id} | |
return json.dumps(result) | |
class URLImageProcessor(BaseImageProcessor): | |
""" | |
utility to download images from the web, save them | |
and resize them. | |
usage: | |
processor = URLImageProcessor(url='http://www.projectsherpa.com/static/img/companies/moat/logo.png') | |
if processor.save(): | |
timeline = processor.rescale(PhotoSize.Timeline) | |
thumbnail = processor.rescale(PhotoSize.Thumbnail, True) # adding True here forces a thumbnail without doing a resize | |
... | |
""" | |
def __init__(self, base_dir=MEDIA_ROOT, **kwargs): | |
BaseImageProcessor.__init__(self, base_dir, **kwargs) | |
self.url = kwargs.pop('url') | |
self.extension = self.get_extension(self.url) | |
def save(self): | |
if '?' in self.url: | |
return False | |
try: | |
f = urllib2.urlopen(self.url) | |
contents = f.read() | |
local_file = open(self.get_filename(), 'wb') | |
local_file.write(contents) | |
local_file.close() | |
return True | |
except (urllib2.HTTPError, urllib2.URLError, socket.timeout, socket.error, ValueError) as e: | |
print 'Download Error', str(e) | |
return False | |
class FileImageProcessor(BaseImageProcessor): | |
""" | |
utility to resize image files | |
usage: | |
processor = FileImageProcessor(filename=filename) | |
# uploaded is of type HttpRequest in this example | |
# see: https://docs.djangoproject.com/en/dev/ref/request-response/#django.http.HttpRequest.read | |
processor.load(uploaded) | |
timeline = processor.rescale(PhotoSize.Timeline) | |
thumbnail = processor.rescale(PhotoSize.Thumbnail, True) | |
""" | |
def __init__(self, base_dir=MEDIA_ROOT, **kwargs): | |
BaseImageProcessor.__init__(self, base_dir, **kwargs) | |
self.filename = kwargs.pop('filename') | |
self.extension = self.get_extension(self.filename) | |
self.contents = None | |
def save(self): | |
try: | |
local_file = open(self.get_filename(), 'wb') | |
local_file.write(self.contents) | |
local_file.close() | |
return True | |
except IOError: | |
return False | |
def load(self, contents): | |
self.contents = contents.read() | |
self.save() | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment