Better handle rotations

This commit is contained in:
Skia 2016-11-20 13:39:04 +01:00
parent 869634d6e1
commit 815ef03860
6 changed files with 55 additions and 10 deletions

View File

@ -12,7 +12,7 @@
{% for r in user.pictures.exclude(picture=None).filter(picture__parent=album) %} {% for r in user.pictures.exclude(picture=None).filter(picture__parent=album) %}
<div style="display: inline-block; border: solid 1px black; width: 9%; margin: 0.1%"> <div style="display: inline-block; border: solid 1px black; width: 9%; margin: 0.1%">
<a href="{{ url("sas:picture", picture_id=r.picture.id) }}#pict"> <a href="{{ url("sas:picture", picture_id=r.picture.id) }}#pict">
<img src="{{ r.picture.as_picture.get_download_url() }}" alt="{{ r.picture.get_display_name() }}" style="max-width: 100%"/> <img src="{{ r.picture.as_picture.get_download_thumb_url() }}" alt="{{ r.picture.get_display_name() }}" style="max-width: 100%"/>
</a> </a>
</div> </div>
{% endfor %} {% endfor %}

View File

@ -1,7 +1,7 @@
# Image utils # Image utils
from io import BytesIO from io import BytesIO
from PIL import Image from PIL import Image, ExifTags
# from exceptions import IOError # from exceptions import IOError
import PIL import PIL
from django.core.files.base import ContentFile from django.core.files.base import ContentFile
@ -25,3 +25,16 @@ def resize_image(im, edge, format):
im.save(fp=content, format=format.upper(), quality=90, optimize=True, progressive=True) im.save(fp=content, format=format.upper(), quality=90, optimize=True, progressive=True)
return ContentFile(content.getvalue()) return ContentFile(content.getvalue())
def exif_auto_rotate(image):
for orientation in ExifTags.TAGS.keys() :
if ExifTags.TAGS[orientation]=='Orientation' : break
exif=dict(image._getexif().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 File

@ -1950,7 +1950,7 @@ msgstr "Erreur de création du dossier %(folder_name)s : %(msg)s"
#: sas/views.py:41 #: sas/views.py:41
#, python-format #, python-format
msgid "Error uploading file %(file_name)s: %(msg)s" msgid "Error uploading file %(file_name)s: %(msg)s"
msgstr "Erreur d'envoie du fichier %(file_name)s : %(msg)s" msgstr "Erreur d'envoi du fichier %(file_name)s : %(msg)s"
#: core/views/forms.py:59 core/views/forms.py:62 #: core/views/forms.py:59 core/views/forms.py:62
msgid "Choose file" msgid "Choose file"

View File

@ -30,6 +30,19 @@ class Picture(SithFile):
def get_download_thumb_url(self): def get_download_thumb_url(self):
return reverse('sas:download_thumb', kwargs={'picture_id': self.id}) return reverse('sas:download_thumb', kwargs={'picture_id': self.id})
def rotate(self, degree):
from PIL import Image
from io import BytesIO
from django.core.files.base import ContentFile
for attr in ['file', 'compressed', 'thumbnail']:
if self.__getattribute__(attr):
im = Image.open(BytesIO(self.__getattribute__(attr).read()))
new_image = BytesIO()
im = im.rotate(degree, expand=True)
im.save(fp=new_image, format=self.mime_type.split('/')[-1].upper(), quality=90, optimize=True, progressive=True)
self.__getattribute__(attr).save(self.name, ContentFile(new_image.getvalue()))
self.save()
def get_next(self): def get_next(self):
return self.parent.children.exclude(is_moderated=False, asked_for_removal=True).filter(id__gt=self.id).order_by('id').first() return self.parent.children.exclude(is_moderated=False, asked_for_removal=True).filter(id__gt=self.id).order_by('id').first()

View File

@ -34,8 +34,12 @@
{% block content %} {% block content %}
{{ print_path(picture.parent) }} {{ picture.get_display_name() }} {{ print_path(picture.parent) }} {{ picture.get_display_name() }}
<h3>{{ picture.get_display_name() }}</h3> <h3>{{ picture.get_display_name() }}</h3>
<div style="display: inline-block; width: 89%; background: #333;" id="pict"> <div style="display: inline-block; width: 89%; background: #333; border: solid #333 2px;" id="pict">
<img src="{{ picture.get_download_compressed_url() }}" alt="{{ picture.get_display_name() }}" style="width: 90%; display: block; margin: auto"/> {% if is_vertical %}
<img src="{{ picture.get_download_compressed_url() }}" alt="{{ picture.get_display_name() }}" style="width: 60%; display: block; margin: auto"/>
{% else %}
<img src="{{ picture.get_download_compressed_url() }}" alt="{{ picture.get_display_name() }}" style="width: 100%; display: block; margin: auto"/>
{% endif %}
</div> </div>
<div style="display: inline-block; width: 10%; vertical-align: top;"> <div style="display: inline-block; width: 10%; vertical-align: top;">
<div> <div>
@ -77,7 +81,9 @@
<a href="{{ picture.get_download_url() }}">{% trans %}HD version{% endtrans %}</a> <a href="{{ picture.get_download_url() }}">{% trans %}HD version{% endtrans %}</a>
</p> </p>
<p style="font-size: smaller;"> <p style="font-size: smaller;">
<a href="?ask_removal">{% trans %}Ask for removal{% endtrans %}</a> <a href="?rotate_left">{% trans %}Rotate left{% endtrans %}</a><br>
<a href="?rotate_right">{% trans %}Rotate right{% endtrans %}</a><br>
<a href="?ask_removal">{% trans %}Ask for removal{% endtrans %}</a><br>
</p> </p>
</div> </div>
{% endblock %} {% endblock %}

View File

@ -10,12 +10,16 @@ from django.core.exceptions import PermissionDenied
from ajax_select import make_ajax_form, make_ajax_field from ajax_select import make_ajax_form, make_ajax_field
from io import BytesIO
from PIL import Image
from core.views import CanViewMixin, CanEditMixin, CanEditPropMixin, CanCreateMixin, TabedViewMixin from core.views import CanViewMixin, CanEditMixin, CanEditPropMixin, CanCreateMixin, TabedViewMixin
from core.views.forms import SelectUser, LoginForm, SelectDate, SelectDateTime from core.views.forms import SelectUser, LoginForm, SelectDate, SelectDateTime
from core.views.files import send_file from core.views.files import send_file
from core.models import SithFile, User from core.models import SithFile, User
from sas.models import Picture, Album, PeoplePictureRelation from sas.models import Picture, Album, PeoplePictureRelation
from core.utils import resize_image, exif_auto_rotate
class SASForm(forms.Form): class SASForm(forms.Form):
album_name = forms.CharField(label=_("Add a new album"), max_length=30, required=False) album_name = forms.CharField(label=_("Add a new album"), max_length=30, required=False)
@ -23,9 +27,6 @@ class SASForm(forms.Form):
required=False) required=False)
def process(self, parent, owner, files, automodere=False): def process(self, parent, owner, files, automodere=False):
from core.utils import resize_image
from io import BytesIO
from PIL import Image
try: try:
if self.cleaned_data['album_name'] != "": if self.cleaned_data['album_name'] != "":
album = Album(parent=parent, name=self.cleaned_data['album_name'], owner=owner, is_moderated=automodere) album = Album(parent=parent, name=self.cleaned_data['album_name'], owner=owner, is_moderated=automodere)
@ -40,14 +41,19 @@ class SASForm(forms.Form):
try: try:
new_file.clean() new_file.clean()
im = Image.open(BytesIO(f.read())) im = Image.open(BytesIO(f.read()))
try:
im = exif_auto_rotate(im)
except: pass
file = resize_image(im, max(im.size), f.content_type.split('/')[-1])
thumb = resize_image(im, 200, f.content_type.split('/')[-1]) thumb = resize_image(im, 200, f.content_type.split('/')[-1])
compressed = resize_image(im, 600, f.content_type.split('/')[-1]) compressed = resize_image(im, 600, f.content_type.split('/')[-1])
new_file.file = file
new_file.file.name = new_file.name
new_file.thumbnail = thumb new_file.thumbnail = thumb
new_file.thumbnail.name = new_file.name new_file.thumbnail.name = new_file.name
new_file.compressed = compressed new_file.compressed = compressed
new_file.compressed.name = new_file.name new_file.compressed.name = new_file.name
new_file.save() new_file.save()
print(new_file.compressed)
except Exception as e: except Exception as e:
self.add_error(None, _("Error uploading file %(file_name)s: %(msg)s") % {'file_name': f, 'msg': repr(e)}) self.add_error(None, _("Error uploading file %(file_name)s: %(msg)s") % {'file_name': f, 'msg': repr(e)})
@ -94,6 +100,10 @@ class PictureView(CanViewMixin, DetailView, FormMixin):
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
self.object = self.get_object() self.object = self.get_object()
self.form = self.get_form() self.form = self.get_form()
if 'rotate_right' in request.GET.keys():
self.object.rotate(270)
if 'rotate_left' in request.GET.keys():
self.object.rotate(90)
if 'remove_user' in request.GET.keys(): if 'remove_user' in request.GET.keys():
try: try:
user = User.objects.filter(id=int(request.GET['remove_user'])).first() user = User.objects.filter(id=int(request.GET['remove_user'])).first()
@ -122,6 +132,9 @@ class PictureView(CanViewMixin, DetailView, FormMixin):
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
kwargs = super(PictureView, self).get_context_data(**kwargs) kwargs = super(PictureView, self).get_context_data(**kwargs)
kwargs['form'] = self.form kwargs['form'] = self.form
im = Image.open(BytesIO(self.object.file.read()))
(w, h) = im.size
kwargs['is_vertical'] = (w / h) < 1
return kwargs return kwargs
def get_success_url(self): def get_success_url(self):