123 lines
4.2 KiB
Python
123 lines
4.2 KiB
Python
import hashlib
|
|
import os
|
|
import shutil
|
|
import uuid
|
|
|
|
from PIL import Image, ExifTags
|
|
from PIL.Image import LANCZOS
|
|
import pkg_resources
|
|
from pyramid.response import FileResponse, Response
|
|
from pyramid.security import authenticated_userid
|
|
from pyramid.view import view_config
|
|
from sqlalchemy.exc import IntegrityError
|
|
import transaction
|
|
import numpy
|
|
|
|
from soter.models import DBSession
|
|
from soter.models.master import Picture, Album
|
|
|
|
|
|
@view_config(request_method='GET', route_name='upload', permission='Albums')
|
|
@view_config(request_method='GET', route_name='picture_id', permission='Albums')
|
|
def html(request):
|
|
package, resource = 'soter:static/index.html'.split(':', 1)
|
|
file = pkg_resources.resource_filename(package, resource)
|
|
return FileResponse(file, request=request)
|
|
|
|
|
|
@view_config(request_method='POST', route_name='api_upload', renderer='json', permission='Albums')
|
|
def upload(request):
|
|
input_file = request.POST['file'].file
|
|
file_id = uuid.uuid4()
|
|
file_path = pkg_resources.resource_filename('soter', 'upload/o/' + str(file_id) + '.jpg')
|
|
album = request.POST['album']
|
|
temp_file_path = file_path + '~'
|
|
input_file.seek(0)
|
|
with open(temp_file_path, 'wb') as output_file:
|
|
shutil.copyfileobj(input_file, output_file)
|
|
pic = process_picture(temp_file_path, str(file_id), uuid.UUID(authenticated_userid(request)), file_id,
|
|
uuid.UUID(album))
|
|
DBSession.add(pic)
|
|
try:
|
|
transaction.commit()
|
|
except IntegrityError as ex:
|
|
transaction.abort()
|
|
os.remove(temp_file_path)
|
|
response = Response("Duplicate file")
|
|
response.status_int = 500
|
|
return response
|
|
else:
|
|
os.rename(temp_file_path, file_path)
|
|
return {'location': file_path}
|
|
|
|
|
|
def process_picture(path, name, user_id, file_id, album_id):
|
|
image = get_image(path)
|
|
img = numpy.array(image)
|
|
img = img[:, :, ::-1].copy()
|
|
|
|
hash = hashlib.sha512(numpy.array(img)).digest()
|
|
picture = Picture(name, hash, user_id, True, file_id)
|
|
picture.albums.append(Album.by_id(album_id))
|
|
return picture
|
|
|
|
|
|
def get_image(path):
|
|
image = Image.open(path)
|
|
orientation = [tag for tag in ExifTags.TAGS.keys() if ExifTags.TAGS[tag] == 'Orientation'][0]
|
|
exif = getattr(image, "_getexif", None)
|
|
if exif is None:
|
|
return image
|
|
exif = image._getexif()
|
|
if exif is None:
|
|
return image
|
|
exif = dict(exif.items())
|
|
if exif[orientation] == 3:
|
|
image = image.rotate(180, expand=True)
|
|
elif exif[orientation] == 6:
|
|
image = image.rotate(270, expand=True)
|
|
elif exif[orientation] == 8:
|
|
image = image.rotate(90, expand=True)
|
|
return image
|
|
|
|
|
|
@view_config(request_method='GET', route_name='picture_raw', permission='Albums')
|
|
def show_raw(request):
|
|
size = request.matchdict['size']
|
|
id = request.matchdict['id']
|
|
package, resource = ('soter:upload/' + size + '/' + id + '.jpg').split(':', 1)
|
|
file = pkg_resources.resource_filename(package, resource)
|
|
if not os.path.isfile(file):
|
|
create_thumbnail(id, size)
|
|
return FileResponse(file, request=request)
|
|
|
|
|
|
def create_thumbnail(id, size):
|
|
file_path = pkg_resources.resource_filename('soter', 'upload/' + size + '/' + id + '.jpg')
|
|
size = tuple([int(i) for i in size.split('x')])
|
|
file = pkg_resources.resource_filename('soter', 'upload/o/' + id + '.jpg')
|
|
image = get_image(file)
|
|
image.thumbnail(size, resample=LANCZOS)
|
|
image.save(file_path)
|
|
|
|
|
|
@view_config(request_method='GET', route_name='api_picture_id', renderer='json', request_param='s', permission='Albums')
|
|
def show_id(request):
|
|
return picture_info(request.matchdict['id'], request.GET['s'], request)
|
|
|
|
|
|
@view_config(request_method='GET', route_name='api_picture_id', renderer='json', permission='Albums')
|
|
def show_id_org(request):
|
|
return picture_info(request.matchdict['id'], 'o', request)
|
|
|
|
|
|
def picture_info(id, size, request):
|
|
if not isinstance(id, Picture):
|
|
picture = Picture.by_id(id)
|
|
else:
|
|
picture = id
|
|
album = {'id': picture.id, 'name': picture.name,
|
|
'imageUrl': request.route_url('picture_raw', id=picture.id, size=size),
|
|
'user': {'id': picture.user_id, 'name': picture.user.name}}
|
|
return album
|