|
|
|
# coding: utf-8
|
|
|
|
|
|
|
|
from django.db import models
|
|
|
|
import seminar.models
|
|
|
|
from django.db.models import Q
|
|
|
|
from django.utils import timezone
|
|
|
|
from django.utils.encoding import force_unicode
|
|
|
|
|
|
|
|
from PIL import Image
|
|
|
|
from PIL.ExifTags import TAGS
|
|
|
|
import os
|
|
|
|
from cStringIO import StringIO
|
|
|
|
from django.core.files.base import ContentFile
|
|
|
|
from datetime import datetime
|
|
|
|
|
|
|
|
from seminar.models import Soustredeni
|
|
|
|
|
|
|
|
VZDY=0
|
|
|
|
ORG=1
|
|
|
|
NIKDY=2
|
|
|
|
VIDITELNOST = (
|
|
|
|
(VZDY, 'Vždy'),
|
|
|
|
(ORG, 'Organizátorům'),
|
|
|
|
(NIKDY, 'Nikdy'),
|
|
|
|
)
|
|
|
|
|
|
|
|
def get_exif(fn):
|
|
|
|
ret = {}
|
|
|
|
info = fn._getexif()
|
|
|
|
for tag, value in info.items():
|
|
|
|
decoded = TAGS.get(tag, tag)
|
|
|
|
ret[decoded] = value
|
|
|
|
return ret
|
|
|
|
|
|
|
|
def flip_horizontal(im): return im.transpose(Image.FLIP_LEFT_RIGHT)
|
|
|
|
def flip_vertical(im): return im.transpose(Image.FLIP_TOP_BOTTOM)
|
|
|
|
def rotate_180(im): return im.transpose(Image.ROTATE_180)
|
|
|
|
def rotate_90(im): return im.transpose(Image.ROTATE_90)
|
|
|
|
def rotate_270(im): return im.transpose(Image.ROTATE_270)
|
|
|
|
def transpose(im): return rotate_90(flip_horizontal(im))
|
|
|
|
def transverse(im): return rotate_90(flip_vertical(im))
|
|
|
|
orientation_funcs = [None,
|
|
|
|
lambda x: x,
|
|
|
|
flip_horizontal,
|
|
|
|
rotate_180,
|
|
|
|
flip_vertical,
|
|
|
|
transpose,
|
|
|
|
rotate_270,
|
|
|
|
transverse,
|
|
|
|
rotate_90
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
cislo_gal = force_unicode(gal.pk)
|
|
|
|
cesta = ""
|
|
|
|
while(not gal.soustredeni):
|
|
|
|
gal = gal.galerie_up
|
|
|
|
return os.path.join('Galerie', "soustredeni_" + force_unicode(gal.soustredeni.pk), "galerie_" + cislo_gal, typ, force_unicode(self.nazev))
|
|
|
|
|
|
|
|
class Obrazek(models.Model):
|
|
|
|
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.")
|
|
|
|
obrazek_stredni = models.ImageField(upload_to=obrazek_filename_stredni, null = True, editable = False)
|
|
|
|
obrazek_maly = models.ImageField(upload_to=obrazek_filename_maly, null = True, editable = False)
|
|
|
|
nazev = models.CharField('Název', max_length=50, blank = True, null = True)
|
|
|
|
popis = models.TextField('Popis', blank = True, null = True)
|
|
|
|
datum_vlozeni = models.DateTimeField('Datum vložení', auto_now_add = True)
|
|
|
|
datum = models.DateTimeField('Datum pořízení fotografie', blank = True, null = True)
|
|
|
|
galerie = models.ForeignKey('Galerie', blank=True, null=True)
|
|
|
|
poradi = models.IntegerField('Pořadí', blank = True, null = True)
|
|
|
|
def __unicode__(self):
|
|
|
|
return self.nazev + " -- " + unicode(self.obrazek_velky.name) + " (" + str(self.datum) + ")"
|
|
|
|
class Meta:
|
|
|
|
verbose_name = 'Obrázek'
|
|
|
|
verbose_name_plural = 'Obrázky'
|
|
|
|
ordering = ['datum']
|
|
|
|
def save(self):
|
|
|
|
original = Image.open(self.obrazek_velky)
|
|
|
|
# vycteni EXIFu
|
|
|
|
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']:
|
|
|
|
datum_string = ":".join(exif['DateTimeOriginal'].split(' ')).split(":")
|
|
|
|
datum_int = []
|
|
|
|
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()
|
|
|
|
|
|
|
|
@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):
|
|
|
|
nazev = models.CharField('Název', max_length=100)
|
|
|
|
datum_vytvoreni = models.DateTimeField('Datum vytvoření', auto_now_add = True)
|
|
|
|
datum_zmeny = models.DateTimeField('Datum poslední změny', auto_now = True)
|
|
|
|
popis = models.TextField('Popis', blank = True, null = True)
|
|
|
|
titulni_obrazek = models.ForeignKey(Obrazek, blank = True, null = True, related_name = "+", on_delete = models.SET_NULL)
|
|
|
|
zobrazit = models.IntegerField('Zobrazit?', default = ORG, choices = VIDITELNOST)
|
|
|
|
galerie_up = models.ForeignKey('Galerie', blank = True, null = True)
|
|
|
|
soustredeni = models.ForeignKey(Soustredeni, blank = True, null = True)
|
|
|
|
poradi = models.IntegerField('Pořadí', blank = True, null = True)
|
|
|
|
|
|
|
|
def __unicode__(self):
|
|
|
|
return self.nazev
|
|
|
|
class Meta:
|
|
|
|
verbose_name = 'Galerie'
|
|
|
|
verbose_name_plural = 'Galerie'
|
|
|
|
|
|
|
|
#def link_na_preview(self):
|
|
|
|
#"""Odkaz na galerii, používá se v admin rozhranní. """
|
|
|
|
#return '<a href="/fotogalerie/galerie/%s/">Preview</a>' % self.id
|
|
|
|
#link_na_preview.allow_tags = True
|
|
|
|
#link_na_preview.short_description = 'Zobrazit galerii'
|
|
|
|
#
|
|
|
|
#def je_publikovano(self):
|
|
|
|
#"""Vraci True, pokud je tato galerie publikovana. """
|
|
|
|
#if self.zobrazit == VZDY:
|
|
|
|
#return True
|
|
|
|
#if self.zobrazit == PODLE_CLANKU:
|
|
|
|
#for clanek in self.clanek_set.all():
|
|
|
|
#if clanek.je_publikovano():
|
|
|
|
#return True
|
|
|
|
#return False
|
|
|
|
#
|
|
|
|
#@staticmethod
|
|
|
|
#def publikovane_galerie():
|
|
|
|
#"""Vraci galerie, ktere uz maji byt publikovane."""
|
|
|
|
#clanky = Blog.models.Clanek.publikovane_clanky()
|
|
|
|
#return Galerie.objects.filter(Q(zobrazit=VZDY) | (Q(clanek__in=clanky) & Q(zobrazit=PODLE_CLANKU))).distinct()
|