hosting/server/imgutil.py (75 lines of code) (raw):

# Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # Image processing functions from StringIO import StringIO try: from PIL import Image from PIL import ImageOps from PIL import ExifTags except: Image = None from base64 import b64encode, b64decode from urllib import urlopen from util import * from sys import debug # Rotate image if needed def rotateimg(img): debug('imgutil.py::rotateimg') if not hasattr(img, '_getexif'): return img exif = img._getexif() if exif is None: return img for tag, value in exif.items(): decoded = ExifTags.TAGS.get(tag, tag) if decoded == 'Orientation': if value == 3: return img.rotate(180) if value == 6: return img.rotate(270) if value == 8: return img.rotate(90) return img # Convert image to a cropped thumbnail def thumbnail(img, size): def intsz(*nums): return tuple(int(round(n)) for n in nums) class imgsz(object): def __init__(self, pair): self.width = float(pair[0]) self.height = float(pair[1]) self.aspect_ratio = self.width / self.height self.size = intsz(self.width, self.height) osz = imgsz(img.size) tsz = imgsz(size) if tsz.aspect_ratio > osz.aspect_ratio: scale = tsz.width / osz.width crop = imgsz((osz.width, tsz.height / scale)) cut = (osz.height - crop.height) / 2 img = img.crop(intsz(0, cut, crop.width, cut + crop.height)) elif tsz.aspect_ratio < osz.aspect_ratio: scale = tsz.height / osz.height crop = imgsz((tsz.width / scale, osz.height)) cut = (osz.width - crop.width) / 2 img = img.crop(intsz(cut, 0, cut + crop.width, crop.height)) return img.resize(tsz.size, Image.ANTIALIAS) # Convert image URL to a 50x50 JPEG def urlto50x50jpeg(url): debug('imgutil.py::urlto50x50jpeg::url', url) if Image is None: return url img = Image.open(StringIO(b64decode(url.split(',')[1])) if url.startswith('data:') else StringIO(urlopen(url).read())) if img.size == (50, 50): debug('imgutil.py::urlto50x50jpeg::res', url) return url thumb = thumbnail(rotateimg(img), (50, 50)) obuf = StringIO() thumb.save(obuf, 'JPEG') res = 'data:image/jpeg;base64,' + b64encode(obuf.getvalue()).replace('\n', '') debug('imgutil.py::urlto50x50jpeg::res', res) return res; # Convert image to a 50x50 JPEG def bufto50x50jpeg(buf): debug('imgutil.py::bufto50x50jpeg') if Image is None: return '' img = Image.open(StringIO(buf)) if img.size == (50, 50): debug('imgutil.py::urlto50x50jpeg::res', url) return url thumb = thumbnail(rotateimg(img), (50, 50)) obuf = StringIO() thumb.save(obuf, 'JPEG') res = 'data:image/jpeg;base64,' + b64encode(obuf.getvalue()).replace('\n', '') debug('imgutil.py::bufto50x50jpeg::res', res) return res