Browse Source

Používej na miniatury django-imagekit

místo vlastních funkcí volaných v save()
* migrace seminar i galerie
* miniatury (a "střední velikosti") se nyní vytvářejí podle potřeby v
  media/CACHE
remotes/origin/imagekit
Matěj Kocián 9 years ago
parent
commit
b3229fafe1
  1. 22
      galerie/migrations/0006_django_imagekit.py
  2. 96
      galerie/models.py
  3. 8
      galerie/templates/galerie/GalerieNahled.html
  4. 1
      requirements.txt
  5. 25
      seminar/migrations/0035_django_imagekit.py
  6. 67
      seminar/models.py

22
galerie/migrations/0006_django_imagekit.py

@ -0,0 +1,22 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('galerie', '0005_obrazek_ordering_datum'),
]
operations = [
migrations.RemoveField(
model_name='obrazek',
name='obrazek_maly',
),
migrations.RemoveField(
model_name='obrazek',
name='obrazek_stredni',
),
]

96
galerie/models.py

@ -5,6 +5,8 @@ import seminar.models
from django.db.models import Q from django.db.models import Q
from django.utils import timezone from django.utils import timezone
from django.utils.encoding import force_unicode from django.utils.encoding import force_unicode
from imagekit.models import ImageSpecField
from imagekit.processors import ResizeToFit, Transpose
from PIL import Image from PIL import Image
from PIL.ExifTags import TAGS from PIL.ExifTags import TAGS
@ -32,47 +34,32 @@ def get_exif(fn):
ret[decoded] = value ret[decoded] = value
return ret return ret
def flip_horizontal(im): return im.transpose(Image.FLIP_LEFT_RIGHT) # tyhle funkce jsou tady jen kvůli starým migracím, které se na ně odkazují
def flip_vertical(im): return im.transpose(Image.FLIP_TOP_BOTTOM) # až se ty migrace někdy squashnou, tak by mělo být možné funkce smazat
def rotate_180(im): return im.transpose(Image.ROTATE_180) def obrazek_filename_maly():
def rotate_90(im): return im.transpose(Image.ROTATE_90) pass
def rotate_270(im): return im.transpose(Image.ROTATE_270) def obrazek_filename_stredni():
def transpose(im): return rotate_90(flip_horizontal(im)) pass
def transverse(im): return rotate_90(flip_vertical(im)) def obrazek_filename_velky():
orientation_funcs = [None, pass
lambda x: x,
flip_horizontal,
rotate_180,
flip_vertical,
transpose,
rotate_270,
transverse,
rotate_90
]
def obrazek_filename(self, filename): def obrazek_filename(self, filename):
return obrazek_filename_obecny(self, filename, "velky")
def obrazek_filename_stredni(self, filename):
return obrazek_filename_obecny(self, filename, "stredni")
def obrazek_filename_maly(self, filename):
return obrazek_filename_obecny(self, filename, "maly")
def obrazek_filename_obecny(self, filename, typ):
gal = self.galerie gal = self.galerie
cislo_gal = force_unicode(gal.pk) cislo_gal = force_unicode(gal.pk)
cesta = "" cesta = ""
while(not gal.soustredeni): while(not gal.soustredeni):
gal = gal.galerie_up gal = gal.galerie_up
return os.path.join('Galerie', "soustredeni_" + force_unicode(gal.soustredeni.pk), "galerie_" + cislo_gal, typ, force_unicode(self.nazev)) return os.path.join('Galerie', "soustredeni_" + force_unicode(gal.soustredeni.pk), "galerie_" + cislo_gal, "velky", force_unicode(self.nazev))
class Obrazek(models.Model): class Obrazek(models.Model):
obrazek_velky = models.ImageField(upload_to=obrazek_filename, obrazek_velky = models.ImageField(upload_to=obrazek_filename,
help_text = "Lze vložit libovolně velký obrázek. Ideální je, aby alespoň jeden rozměr měl alespoň 500px.") help_text = "Lze vložit libovolně velký obrázek. Ideální je, aby alespoň jeden rozměr měl alespoň 500px.")
obrazek_stredni = models.ImageField(upload_to=obrazek_filename_stredni, null = True, editable = False) obrazek_stredni = ImageSpecField(source='obrazek_velky',
obrazek_maly = models.ImageField(upload_to=obrazek_filename_maly, null = True, editable = False) processors=[Transpose(Transpose.AUTO), ResizeToFit(900, 675, upscale=False)],
options={'quality': 95})
obrazek_maly = ImageSpecField(source='obrazek_velky',
processors=[Transpose(Transpose.AUTO), ResizeToFit(167, 167, upscale=False)],
options={'quality': 95})
nazev = models.CharField('Název', max_length=50, blank = True, null = True) nazev = models.CharField('Název', max_length=50, blank = True, null = True)
popis = models.TextField('Popis', blank = True, null = True) popis = models.TextField('Popis', blank = True, null = True)
datum_vlozeni = models.DateTimeField('Datum vložení', auto_now_add = True) datum_vlozeni = models.DateTimeField('Datum vložení', auto_now_add = True)
@ -89,56 +76,11 @@ class Obrazek(models.Model):
original = Image.open(self.obrazek_velky) original = Image.open(self.obrazek_velky)
# vycteni EXIFu # vycteni EXIFu
exif = get_exif(original) exif = get_exif(original)
# otoceni podle EXIFu
if exif['Orientation']:
f = orientation_funcs[exif['Orientation']]
original_otoceny = f(original)
original_otoceny.format = original.format
original = original_otoceny
# datum podle EXIfu
if exif['DateTimeOriginal']: if exif['DateTimeOriginal']:
datum_string = ":".join(exif['DateTimeOriginal'].split(' ')).split(":") datum_ints = map(int, ":".join(exif['DateTimeOriginal'].split(' ')).split(":"))
datum_int = [] self.datum = datetime(*datum_ints)
for retezec in datum_string:
datum_int.append(int(retezec))
self.datum = datetime(datum_int[0], datum_int[1], datum_int[2],
datum_int[3], datum_int[4], datum_int[5])
jmeno = os.path.basename(self.obrazek_velky.file.name)
if not self.obrazek_stredni:
Obrazek._vyrobMiniaturu(original, jmeno, 1024, self.obrazek_stredni)
if not self.obrazek_maly:
Obrazek._vyrobMiniaturu(original, jmeno, 200, self.obrazek_maly)
super(Obrazek, self).save() super(Obrazek, self).save()
@staticmethod
def _vyrobMiniaturu(original, jmeno, maximum, field):
zmensenina = Obrazek._zmensiObrazek(original, maximum)
f = StringIO()
try:
zmensenina.save(f, format=original.format)
data = ContentFile(f.getvalue())
finally:
f.close()
field.save(jmeno, data, save = False)
@staticmethod
def _zmensiObrazek(original, maximum):
"""Preskaluje obrazek tak, aby byl zachovan pomer stran a zadny rozmer
nepresahoval maxRozmer. Pokud zadny rozmer nepresahuje maxRozmer, tak
vrati puvodni obrazek (tj. nedojde ke zvetseni obrazku)."""
novaVelikost = Obrazek._zmensiVelikost(original.size, maximum)
return original.resize(novaVelikost, Image.ANTIALIAS)
@staticmethod
def _zmensiVelikost(velikost, maximum):
maximum = float(maximum)
w, h = velikost
soucasneMaximum = max(w, h)
if soucasneMaximum <= maximum:
return velikost
pomer = maximum/soucasneMaximum
return (int(w * pomer), int(h * pomer))
class Galerie(models.Model): class Galerie(models.Model):
nazev = models.CharField('Název', max_length=100) nazev = models.CharField('Název', max_length=100)

8
galerie/templates/galerie/GalerieNahled.html

@ -45,8 +45,8 @@ Galerie {{galerie.nazev}}
{% if galerie.titulni_obrazek %} {% if galerie.titulni_obrazek %}
{% with galerie.titulni_obrazek.obrazek_maly as obrazek %} {% with galerie.titulni_obrazek.obrazek_maly as obrazek %}
<img src="{{ obrazek.url }}" <img src="{{ obrazek.url }}"
width={% widthratio obrazek.width 200 167 %} width="{{ obrazek.width }}"
height={% widthratio obrazek.height 200 167 %} /> height="{{ obrazek.height }}" />
{% endwith %} {% endwith %}
{% endif %} {% endif %}
<div> <div>
@ -76,8 +76,8 @@ Galerie {{galerie.nazev}}
{% for obrazek in obrazky %} {% for obrazek in obrazky %}
<a title="Zobrazit tuto fotografii" href="./{{obrazek.pk}}#nahoru" class="galerie_nahled"><span class="vystredeno"></span><img <a title="Zobrazit tuto fotografii" href="./{{obrazek.pk}}#nahoru" class="galerie_nahled"><span class="vystredeno"></span><img
src="{{obrazek.obrazek_maly.url}}" src="{{obrazek.obrazek_maly.url}}"
width={% widthratio obrazek.obrazek_maly.width 200 167 %} width="{{ obrazek.obrazek_maly.width }}"
height={% widthratio obrazek.obrazek_maly.height 200 167 %} /> height="{{ obrazek.obrazek_maly.height }}" />
</a> </a>
{% endfor %} {% endfor %}
<br> <br>

1
requirements.txt

@ -23,6 +23,7 @@ django-flat-theme==0.9.3
django-taggit==0.17 django-taggit==0.17
django-autocomplete-light==2.2.6 django-autocomplete-light==2.2.6
django-crispy-forms==1.4.0 django-crispy-forms==1.4.0
django-imagekit==3.2.7
# Comments # Comments
akismet==0.2.0 akismet==0.2.0

25
seminar/migrations/0035_django_imagekit.py

@ -0,0 +1,25 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
import imagekit.models.fields
class Migration(migrations.Migration):
dependencies = [
('seminar', '0034_reseni_forma_default_email'),
]
operations = [
migrations.RemoveField(
model_name='organizator',
name='foto_male',
),
migrations.AlterField(
model_name='organizator',
name='foto',
field=imagekit.models.fields.ProcessedImageField(help_text=b'Vlo\xc5\xbe fotografii organiz\xc3\xa1tora o libovoln\xc3\xa9 velikosti', upload_to=b'image_organizatori/velke/%Y/', null=True, verbose_name=b'Fotografie organiz\xc3\xa1tora', blank=True),
preserve_default=True,
),
]

67
seminar/models.py

@ -11,6 +11,8 @@ from django.utils.encoding import force_unicode
from django.utils.text import slugify from django.utils.text import slugify
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.core.cache import cache from django.core.cache import cache
from imagekit.models import ImageSpecField, ProcessedImageField
from imagekit.processors import ResizeToFit, Transpose
from PIL import Image from PIL import Image
import os import os
@ -785,11 +787,19 @@ class Organizator(models.Model):
"'Přednáší na MFF'") "'Přednáší na MFF'")
strucny_popis_organizatora = models.TextField('Stručný popis organizátora', strucny_popis_organizatora = models.TextField('Stručný popis organizátora',
null = True, blank = True) null = True, blank = True)
foto = models.ImageField('Fotografie organizátora', foto = ProcessedImageField(verbose_name='Fotografie organizátora',
upload_to='image_organizatori/velke/%Y/', null = True, blank = True, upload_to='image_organizatori/velke/%Y/', null = True, blank = True,
help_text = 'Vlož fotografii organizátora o libovolné velikosti') help_text = 'Vlož fotografii organizátora o libovolné velikosti',
foto_male = models.ImageField(upload_to='image_organizatori/male/%Y/', processors=[
null = True, blank = True, editable = False) Transpose(Transpose.AUTO),
ResizeToFit(500, 500, upscale=False)
],
options={'quality': 95})
foto_male = ImageSpecField(source='foto',
processors=[
ResizeToFit(200, 200, upscale=False)
],
options={'quality': 95})
def __str__(self): def __str__(self):
return str(self.user) return str(self.user)
@ -797,52 +807,3 @@ class Organizator(models.Model):
class Meta: class Meta:
verbose_name = 'Organizátor' verbose_name = 'Organizátor'
verbose_name_plural = 'Organizátoři' verbose_name_plural = 'Organizátoři'
def save(self):
# v databázi uložený záznam o organizátorovi
puvodni = None
# pokud už organizátor v databázi existuje, nastav puvodni
if self.id is not None:
puvodni = Organizator.objects.get(id=self.id)
# pokud nahráváme fotku
if self.foto:
# a je jiná než ta stará
if not puvodni or puvodni.foto != self.foto:
# uložíme ji
original = Image.open(self.foto)
jmeno = os.path.basename(self.foto.file.name)
Organizator._vyrobMiniaturu(original, jmeno, 500, self.foto)
Organizator._vyrobMiniaturu(original, jmeno, 200, self.foto_male)
super(Organizator, self).save()
@staticmethod
def _vyrobMiniaturu(original, jmeno, maximum, field):
zmensenina = Organizator._zmensiObrazek(original, maximum)
f = StringIO()
try:
zmensenina.save(f, format=original.format)
data = ContentFile(f.getvalue())
finally:
f.close()
field.save(jmeno, data, save = False)
@staticmethod
def _zmensiObrazek(original, maximum):
"""Preskaluje obrazek tak, aby byl zachovan pomer stran
a zadny rozmer nepresahoval maxRozmer. Pokud zadny rozmer
nepresahuje maxRozmer, tak vrati puvodni obrazek
(tj. nedojde ke zvetseni obrazku)."""
novaVelikost = Organizator._zmensiVelikost(original.size, maximum)
return original.resize(novaVelikost, Image.ANTIALIAS)
@staticmethod
def _zmensiVelikost(velikost, maximum):
maximum = float(maximum)
w, h = velikost
soucasneMaximum = max(w, h)
if soucasneMaximum <= maximum:
return velikost
pomer = maximum/soucasneMaximum
return (int(w * pomer), int(h * pomer))

Loading…
Cancel
Save