diff options
Diffstat (limited to 'app/media')
-rw-r--r-- | app/media/0002_auto_20201201_2054.py | 46 | ||||
-rw-r--r-- | app/media/0003_auto_20201201_2055.py | 118 | ||||
-rw-r--r-- | app/media/admin.py | 49 | ||||
-rw-r--r-- | app/media/migrations/0001_initial.py | 30 | ||||
-rw-r--r-- | app/media/migrations/0002_auto_20211030_1634.py | 38 | ||||
-rw-r--r-- | app/media/models.py | 215 | ||||
-rw-r--r-- | app/media/readexif.py | 76 | ||||
-rw-r--r-- | app/media/static/image-preview.js | 2 | ||||
-rw-r--r-- | app/media/templatetags/get_image_by_size.py | 2 | ||||
-rw-r--r-- | app/media/utils.py | 24 | ||||
-rw-r--r-- | app/media/views.py | 24 |
11 files changed, 455 insertions, 169 deletions
diff --git a/app/media/0002_auto_20201201_2054.py b/app/media/0002_auto_20201201_2054.py new file mode 100644 index 0000000..843f48b --- /dev/null +++ b/app/media/0002_auto_20201201_2054.py @@ -0,0 +1,46 @@ +# Generated by Django 3.1 on 2020-12-01 19:26 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('media', '0001_initial'), + ] + + operations = [ + migrations.RunSQL(""" + INSERT INTO media_luximagesize ( + id, + name, + width, + height, + quality + ) + SELECT + id, + name, + width, + height, + quality + FROM + photos_luximagesize; + """, reverse_sql=""" + INSERT INTO photos_luximagesize ( + id, + name, + width, + height, + quality + ) + SELECT + id, + name, + width, + height, + quality + FROM + media_luximagesize; + """) + ] diff --git a/app/media/0003_auto_20201201_2055.py b/app/media/0003_auto_20201201_2055.py new file mode 100644 index 0000000..4aeec12 --- /dev/null +++ b/app/media/0003_auto_20201201_2055.py @@ -0,0 +1,118 @@ +# Generated by Django 3.1 on 2020-12-01 20:49 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('media', '0002_auto_20201201_2054'), + ] + + operations = [ + migrations.RunSQL(""" + INSERT INTO media_luximage ( + id, + image, + title, + alt, + photo_credit_source, + photo_credit_url, + caption, + pub_date, + height, + width, + is_public, + exif_raw, + exif_aperture, + exif_make, + exif_model, + exif_exposure, + exif_iso, + exif_focal_length, + exif_lens, + exif_date, + point, + location, + sizes + ) + SELECT + id, + image, + title, + alt, + photo_credit_source, + photo_credit_url, + caption, + pub_date, + height, + width, + is_public, + exif_raw, + exif_aperture, + exif_make, + exif_model, + exif_exposure, + exif_iso, + exif_focal_length, + exif_lens, + exif_date, + point, + location, + sizes + FROM + photos_luximage; + """, reverse_sql=""" + INSERT INTO photos_luximage ( + id, + image, + title, + alt, + photo_credit_source, + photo_credit_url, + caption, + pub_date, + height, + width, + is_public, + sizes, + exif_raw, + exif_aperture, + exif_make, + exif_model, + exif_exposure, + exif_iso, + exif_focal_length, + exif_lens, + exif_date, + point, + location + ) + SELECT + id, + image, + title, + alt, + photo_credit_source, + photo_credit_url, + caption, + pub_date, + height, + width, + is_public, + sizes, + exif_raw, + exif_aperture, + exif_make, + exif_model, + exif_exposure, + exif_iso, + exif_focal_length, + exif_lens, + exif_date, + point, + location + FROM + media_luximage; + """) + ] diff --git a/app/media/admin.py b/app/media/admin.py index 12d0509..50eb879 100644 --- a/app/media/admin.py +++ b/app/media/admin.py @@ -1,12 +1,15 @@ from django.contrib import admin +from django import forms from django.contrib.gis.admin import OSMGeoAdmin - -from .models import LuxImage, LuxGallery, LuxImageSize, LuxVideo, LuxAudio +from .models import LuxImage, LuxGallery, LuxImageSize, LuxVideo +from django.shortcuts import render +from django.contrib.admin import helpers +from django.http import HttpResponseRedirect @admin.register(LuxImageSize) class LuxImageSizeAdmin(OSMGeoAdmin): - list_display = ('name', 'width', 'height', 'quality') + list_display = ('name','slug', 'width', 'height', 'quality') @admin.register(LuxVideo) @@ -18,20 +21,44 @@ class LuxVideoAdmin(OSMGeoAdmin): class LuxImageAdmin(OSMGeoAdmin): list_display = ('pk', 'admin_thumbnail', 'pub_date', 'caption') list_filter = ('pub_date',) - search_fields = ['title', 'caption'] + search_fields = ['title', 'caption', 'alt'] # Options for OSM map Using custom ESRI topo map + default_lon = -9285175 + default_lat = 4025046 + default_zoom = 6 + units = True + scrollable = False + map_width = 700 + map_height = 425 + map_template = 'gis/admin/osm.html' + openlayers_url = '/static/admin/js/OpenLayers.js' fieldsets = ( (None, { - 'fields': ('title', ('image'), 'pub_date', 'sizes', 'alt', 'caption', ('is_public'), ('photo_credit_source', 'photo_credit_url')) + 'fields': ( + 'image', + 'alt', + 'sizes', + 'caption', + 'pub_date', + 'title', + ) + }), + ('Exif and Other Data', { + 'classes': ('collapse',), + 'fields': ( + 'point', + ('is_public'), + ('photo_credit_source', 'photo_credit_url'), + 'exif_raw', 'exif_aperture', 'exif_make', 'exif_model', 'exif_exposure', 'exif_iso', 'exif_focal_length', 'exif_lens', 'exif_date', 'height', 'width'), }), ) + def save_related(self, request, form, formsets, change): + super(LuxImageAdmin, self).save_related(request, form, formsets, change) + if not form.instance.sizes.all(): + print("there are no sizes") + form.instance.sizes.add(*LuxImageSize.objects.filter(slug__in=["picwide-sm", "picwide-med", "picwide"])) + class Media: js = ('image-preview.js', 'next-prev-links.js') - - -@admin.register(LuxAudio) -class LuxAudioAdmin(OSMGeoAdmin): - list_display = ('pk', 'title', 'pub_date') - list_filter = ('pub_date',) diff --git a/app/media/migrations/0001_initial.py b/app/media/migrations/0001_initial.py index 8ca4631..886a36e 100644 --- a/app/media/migrations/0001_initial.py +++ b/app/media/migrations/0001_initial.py @@ -1,6 +1,7 @@ -# Generated by Django 3.1.3 on 2020-11-30 22:44 +# Generated by Django 4.1.3 on 2022-12-02 20:09 import datetime +import django.contrib.gis.db.models.fields from django.db import migrations, models import django.db.models.deletion import media.models @@ -17,7 +18,7 @@ class Migration(migrations.Migration): migrations.CreateModel( name='LuxAudio', fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('title', models.CharField(max_length=200)), ('subtitle', models.CharField(blank=True, max_length=200)), ('slug', models.SlugField(blank=True, unique_for_date='pub_date')), @@ -26,6 +27,7 @@ class Migration(migrations.Migration): ('pub_date', models.DateTimeField(default=datetime.datetime.now)), ('mp3', models.FileField(blank=True, null=True, upload_to=media.models.get_audio_upload_path)), ('ogg', models.FileField(blank=True, null=True, upload_to=media.models.get_audio_upload_path)), + ('point', django.contrib.gis.db.models.fields.PointField(blank=True, null=True, srid=4326)), ], options={ 'verbose_name': 'Audio', @@ -37,8 +39,9 @@ class Migration(migrations.Migration): migrations.CreateModel( name='LuxImageSize', fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('name', models.CharField(blank=True, max_length=30, null=True)), + ('slug', models.SlugField(blank=True, null=True)), ('width', models.IntegerField(blank=True, null=True)), ('height', models.IntegerField(blank=True, null=True)), ('quality', models.IntegerField()), @@ -51,7 +54,7 @@ class Migration(migrations.Migration): migrations.CreateModel( name='LuxVideo', fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('video_mp4', models.FileField(blank=True, null=True, upload_to=media.models.get_vid_upload_path)), ('video_webm', models.FileField(blank=True, null=True, upload_to=media.models.get_vid_upload_path)), ('video_poster', models.FileField(blank=True, null=True, upload_to=media.models.get_vid_upload_path)), @@ -70,7 +73,7 @@ class Migration(migrations.Migration): migrations.CreateModel( name='LuxImage', fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('image', models.FileField(blank=True, null=True, upload_to=media.models.get_upload_path)), ('title', models.CharField(blank=True, max_length=300, null=True)), ('alt', models.CharField(blank=True, max_length=300, null=True)), @@ -78,10 +81,21 @@ class Migration(migrations.Migration): ('photo_credit_url', models.CharField(blank=True, max_length=300, null=True)), ('caption', models.TextField(blank=True, null=True)), ('pub_date', models.DateTimeField(default=datetime.datetime.now)), + ('exif_raw', models.TextField(blank=True, null=True)), + ('exif_aperture', models.CharField(blank=True, max_length=50, null=True)), + ('exif_make', models.CharField(blank=True, max_length=50, null=True)), + ('exif_model', models.CharField(blank=True, max_length=50, null=True)), + ('exif_exposure', models.CharField(blank=True, max_length=50, null=True)), + ('exif_iso', models.CharField(blank=True, max_length=50, null=True)), + ('exif_focal_length', models.CharField(blank=True, max_length=50, null=True)), + ('exif_lens', models.CharField(blank=True, max_length=50, null=True)), + ('exif_date', models.DateTimeField(blank=True, null=True)), ('height', models.CharField(blank=True, max_length=6, null=True)), ('width', models.CharField(blank=True, max_length=6, null=True)), + ('point', django.contrib.gis.db.models.fields.PointField(blank=True, null=True, srid=4326)), ('is_public', models.BooleanField(default=True)), - ('sizes', models.ManyToManyField(blank=True, to='media.LuxImageSize')), + ('sizes_cache', models.CharField(blank=True, max_length=300, null=True)), + ('sizes', models.ManyToManyField(blank=True, related_name='sizes', to='media.luximagesize')), ], options={ 'verbose_name_plural': 'Images', @@ -92,14 +106,14 @@ class Migration(migrations.Migration): migrations.CreateModel( name='LuxGallery', fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('title', models.CharField(blank=True, max_length=300)), ('description', models.TextField(blank=True, null=True)), ('slug', models.CharField(blank=True, max_length=300)), ('pub_date', models.DateTimeField(null=True)), ('is_public', models.BooleanField(default=True)), ('caption_style', models.CharField(blank=True, max_length=400, null=True)), - ('images', models.ManyToManyField(to='media.LuxImage')), + ('images', models.ManyToManyField(to='media.luximage')), ('thumb', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='gallery_thumb', to='media.luximage')), ], options={ diff --git a/app/media/migrations/0002_auto_20211030_1634.py b/app/media/migrations/0002_auto_20211030_1634.py deleted file mode 100644 index abebed9..0000000 --- a/app/media/migrations/0002_auto_20211030_1634.py +++ /dev/null @@ -1,38 +0,0 @@ -# Generated by Django 3.2.8 on 2021-10-30 16:34 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('media', '0001_initial'), - ] - - operations = [ - migrations.AlterField( - model_name='luxaudio', - name='id', - field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'), - ), - migrations.AlterField( - model_name='luxgallery', - name='id', - field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'), - ), - migrations.AlterField( - model_name='luximage', - name='id', - field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'), - ), - migrations.AlterField( - model_name='luximagesize', - name='id', - field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'), - ), - migrations.AlterField( - model_name='luxvideo', - name='id', - field=models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'), - ), - ] diff --git a/app/media/models.py b/app/media/models.py index 190026f..dcf7ccc 100644 --- a/app/media/models.py +++ b/app/media/models.py @@ -1,28 +1,28 @@ import os.path import io import datetime +from pathlib import Path from PIL import Image from django.core.exceptions import ValidationError -from django.db import models +from django.contrib.gis.db import models from django.contrib.sitemaps import Sitemap -from django.utils.encoding import force_text +from django.db.models.signals import post_save +from django.dispatch import receiver +from django.db.models.signals import m2m_changed from django.utils.functional import cached_property from django.urls import reverse from django.apps import apps from django.utils.html import format_html -from django.utils.text import slugify from django.conf import settings from django import forms -from taggit.managers import TaggableManager - from resizeimage.imageexceptions import ImageSizeError +from taggit.managers import TaggableManager + +from .readexif import readexif from .utils import resize_image -from django.db.models.signals import post_save -from django.dispatch import receiver -from django.db.models.signals import m2m_changed def get_upload_path(self, filename): @@ -39,6 +39,7 @@ def get_audio_upload_path(self, filename): class LuxImageSize(models.Model): name = models.CharField(null=True, blank=True, max_length=30) + slug = models.SlugField(null=True, blank=True) width = models.IntegerField(null=True, blank=True) height = models.IntegerField(null=True, blank=True) quality = models.IntegerField() @@ -63,10 +64,21 @@ class LuxImage(models.Model): photo_credit_url = models.CharField(null=True, blank=True, max_length=300) caption = models.TextField(blank=True, null=True) pub_date = models.DateTimeField(default=datetime.datetime.now) + exif_raw = models.TextField(blank=True, null=True) + exif_aperture = models.CharField(max_length=50, blank=True, null=True) + exif_make = models.CharField(max_length=50, blank=True, null=True) + exif_model = models.CharField(max_length=50, blank=True, null=True) + exif_exposure = models.CharField(max_length=50, blank=True, null=True) + exif_iso = models.CharField(max_length=50, blank=True, null=True) + exif_focal_length = models.CharField(max_length=50, blank=True, null=True) + exif_lens = models.CharField(max_length=50, blank=True, null=True) + exif_date = models.DateTimeField(blank=True, null=True) height = models.CharField(max_length=6, blank=True, null=True) width = models.CharField(max_length=6, blank=True, null=True) + point = models.PointField(null=True, blank=True) is_public = models.BooleanField(default=True) - sizes = models.ManyToManyField(LuxImageSize, blank=True) + sizes = models.ManyToManyField(LuxImageSize, blank=True, related_name='sizes') + sizes_cache = models.CharField(null=True, blank=True, max_length=300) class Meta: ordering = ('-pub_date', 'id') @@ -85,10 +97,7 @@ class LuxImage(models.Model): def get_admin_image(self): for size in self.sizes.all(): if size.width and size.width <= 820 or size.height and size.height <= 800: - return self.get_image_by_size(size.name) - - def get_admin_insert(self): - return "/media/images/%s/%s_tn.%s" % (self.pub_date.strftime("%Y"), self.get_image_name(), self.get_image_ext()) + return self.get_image_url_by_size(size.name) def get_largest_image(self): t = [] @@ -98,74 +107,70 @@ class LuxImage(models.Model): t.reverse() return self.get_image_path_by_size(t[0]) - def get_image_name(self): - return self.image.url.split("original/")[1][5:-4] - - def get_image_ext(self): - return self.image.url[-3:] - @cached_property - def get_featured_jrnl(self): - ''' cached version of getting the primary image for archive page''' - return "%s%s/%s_%s.%s" % (settings.IMAGES_URL, self.pub_date.strftime("%Y"), self.get_image_name(), 'featured_jrnl', self.get_image_ext()) + def image_name(self): + return os.path.basename(self.image.path)[:-4] @cached_property - def get_picwide_sm(self): - ''' cached version of getting the second image for archive page''' - return "%s%s/%s_%s.%s" % (settings.IMAGES_URL, self.pub_date.strftime("%Y"), self.get_image_name(), 'picwide-sm', self.get_image_ext()) + def image_ext(self): + return self.image.url[-3:] @cached_property + def get_image_filename(self): + return os.path.basename(self.image.path) + + @property def get_srcset(self): srcset = "" length = len(self.sizes.all()) print(length) loopnum = 1 for size in self.sizes.all(): - srcset += "%s%s/%s_%s.%s %sw" % (settings.IMAGES_URL, self.pub_date.strftime("%Y"), self.get_image_name(), size.name, self.get_image_ext(), size.width) + srcset += "%s%s/%s_%s.%s %sw" % (settings.IMAGES_URL, self.pub_date.strftime("%Y"), self.image_name, size.slug, self.image_ext, size.width) if loopnum < length: srcset += ", " loopnum = loopnum+1 return srcset - @cached_property + @property def get_src(self): src = "" if self.sizes.all().count() > 1: - src += "%s%s/%s_%s.%s" % (settings.IMAGES_URL, self.pub_date.strftime("%Y"), self.get_image_name(), 'picwide-med', self.get_image_ext()) + src = self.get_image_url_by_size('picwide-med') else: - src += "%s%s/%s_%s.%s" % (settings.IMAGES_URL, self.pub_date.strftime("%Y"), self.get_image_name(), [size.name for size in self.sizes.all()], self.get_image_ext()) + size = "".join(size.name for size in self.sizes.all()) + src = self.get_image_url_by_size(size) return src - def get_image_by_size(self, size="original"): - base = self.get_image_name() - if size == "admin_insert": - return "images/%s/%s.%s" % (self.pub_date.strftime("%Y"), base, self.get_image_ext()) + def get_image_url_by_size(self, size="original"): if size == "original": - return "%soriginal/%s/%s.%s" % (settings.IMAGES_URL, self.pub_date.strftime("%Y"), base, self.get_image_ext()) + return "%soriginal/%s/%s.%s" % (settings.IMAGES_URL, self.pub_date.strftime("%Y"), self.image_name, self.image_ext) + if size == "admin_insert": + return "images/%s/%s.%s" % (self.pub_date.strftime("%Y"), self.image_name, self.image_ext) else: - if size != 'tn': - s = LuxImageSize.objects.get(name=size) - if s not in self.sizes.all(): - print("new size is "+s.name) - self.sizes.add(s) - return "%s%s/%s_%s.%s" % (settings.IMAGES_URL, self.pub_date.strftime("%Y"), base, size, self.get_image_ext()) + luximagesize = LuxImageSize.objects.get(slug=size) + #if luximagesize not in self.get_sizes: + #self.sizes.add(luximagesize) + return "%s%s/%s_%s.%s" % (settings.IMAGES_URL, self.pub_date.strftime("%Y"), self.image_name, luximagesize.slug, self.image_ext) def get_image_path_by_size(self, size="original"): - base = self.get_image_name() if size == "original": - return "%s/original/%s/%s.%s" % (settings.IMAGES_ROOT, self.pub_date.strftime("%Y"), base, self.get_image_ext()) + return self.image.path else: - return "%s/%s/%s_%s.%s" % (settings.IMAGES_ROOT, self.pub_date.strftime("%Y"), base, size, self.get_image_ext()) + luximagesize = LuxImageSize.objects.get(slug=size) + return "%s/%s/%s_%s.%s" % (settings.IMAGES_ROOT, self.pub_date.strftime("%Y"), self.image_name, luximagesize.slug, self.image_ext) + @cached_property def get_thumbnail_url(self): - return self.get_image_by_size("tn") + return self.get_image_url_by_size("tn") def admin_thumbnail(self): - return format_html('<a href="%s"><img src="%s"></a>' % (self.get_image_by_size(), self.get_image_by_size("tn"))) + return format_html('<a href="%s"><img src="%s"></a>' % (self.get_image_url_by_size(), self.get_image_url_by_size("tn"))) admin_thumbnail.short_description = 'Thumbnail' + @property def get_sizes(self): - return self.sizes.all() + return self.sizes_cache.split(",") @property def get_previous_published(self): @@ -196,6 +201,9 @@ class LuxImage(models.Model): return False def save(self, *args, **kwargs): + created = self.pk is None + if not created: + self.sizes_cache = ",".join(s.slug for s in self.sizes.all()) super(LuxImage, self).save() @@ -270,6 +278,7 @@ class LuxAudio(models.Model): pub_date = models.DateTimeField(default=datetime.datetime.now) mp3 = models.FileField(blank=True, null=True, upload_to=get_audio_upload_path) ogg = models.FileField(blank=True, null=True, upload_to=get_audio_upload_path) + point = models.PointField(blank=True, null=True) class Meta: ordering = ('-pub_date',) @@ -283,6 +292,9 @@ class LuxAudio(models.Model): def get_absolute_url(self): return reverse("prompt:detail", kwargs={"slug": self.slug}) + def get_image_url_by_size(self, size="original"): + pass + @property def get_previous_published(self): return self.get_previous_by_pub_date(status__exact=1) @@ -310,51 +322,84 @@ class LuxAudio(models.Model): def save(self, *args, **kwargs): md = render_images(self.body_markdown) self.body_html = markdown_to_html(md) + if not self.point: + self.point = CheckIn.objects.latest().point super(LuxAudio, self).save(*args, **kwargs) @receiver(post_save, sender=LuxImage) def post_save_events(sender, update_fields, created, instance, **kwargs): - if instance.exif_raw == '': - filename, file_extension = os.path.splitext(instance.image.path) - if file_extension != ".mp4": - img = Image.open(instance.image.path) - instance.height = img.height - instance.width = img.width - post_save.disconnect(post_save_events, sender=LuxImage) - instance.save() - post_save.connect(post_save_events, sender=LuxImage) + if created: + if instance.exif_raw == '': + instance = readexif(instance) + instance.sizes.add(LuxImageSize.objects.get(slug="tn")) + img = Image.open(instance.image.path) + instance.height = img.height + instance.width = img.width + post_save.disconnect(post_save_events, sender=LuxImage) + instance.save() + post_save.connect(post_save_events, sender=LuxImage) @receiver(m2m_changed, sender=LuxImage.sizes.through) def update_photo_sizes(sender, instance, **kwargs): - base_path = "%s/%s/" % (settings.IMAGES_ROOT, instance.pub_date.strftime("%Y")) - filename, file_extension = os.path.splitext(instance.image.path) - if file_extension != ".mp4": - img = Image.open(instance.image.path) - resize_image(img, 160, None, 78, base_path, "%s_tn.%s" % (instance.get_image_name(), instance.get_image_ext())) - for size in instance.sizes.all(): - if size.width: - print("Image width is:"+str(img.width)) - try: - if size.width <= img.width: - resize_image(img, size.width, None, size.quality, base_path, "%s_%s.%s" % (instance.get_image_name(), slugify(size.name), instance.get_image_ext())) - else: - raise ValidationError({'items': ["Size is larger than source image"]}) - except ImageSizeError: - m2m_changed.disconnect(update_photo_sizes, sender=LuxImage.sizes.through) - instance.sizes.remove(size) - m2m_changed.connect(update_photo_sizes, sender=LuxImage.sizes.through) - if size.height: - try: - if size.height <= img.height: - resize_image(img, None, size.height, size.quality, base_path, "%s_%s.%s" % (instance.get_image_name(), slugify(size.name), instance.get_image_ext())) - - else: - pass - except ImageSizeError: - m2m_changed.disconnect(update_photo_sizes, sender=LuxImage.sizes.through) - instance.sizes.remove(size) - m2m_changed.connect(update_photo_sizes, sender=LuxImage.sizes.through) - - + # update the local cache of sizes + sizes = instance.sizes.all() + if sizes: + instance.sizes_cache = ",".join(s.slug for s in sizes) + instance.save() + for size in instance.get_sizes: + print("SIZE is: %s" % size) + # check each size and see if there's an image there already + my_file = Path(instance.get_image_path_by_size(size)) + if not my_file.is_file(): + #file doesn't exist, so create it + new_size = LuxImageSize.objects.get(slug=size) + if new_size.width: + img = Image.open(instance.image.path) + try: + if new_size.width <= img.width: + resize_image(img, new_size.width, None, new_size.quality, instance.get_image_path_by_size(size)) + else: + raise ValidationError({'items': ["Size is larger than source image"]}) + except ImageSizeError: + m2m_changed.disconnect(update_photo_sizes, sender=LuxImage.sizes.through) + instance.sizes.remove(new_size) + m2m_changed.connect(update_photo_sizes, sender=LuxImage.sizes.through) + if new_size.height: + img = Image.open(instance.image.path) + try: + if new_size.height <= img.height: + resize_image(img, None, new_size.height, new_size.quality, instance.get_image_path_by_size(size)) + else: + pass + except ImageSizeError: + m2m_changed.disconnect(update_photo_sizes, sender=LuxImage.sizes.through) + instance.sizes.remove(new_size) + m2m_changed.connect(update_photo_sizes, sender=LuxImage.sizes.through) + else: + # file exists, might add something here to force it to do the above when I want + print("file %s exists" % size) + pass + + +def generate_image(luximage, size): + new_size = LuxImageSize.objects.get(slug=size) + if new_size.width: + img = Image.open(luximage.image.path) + try: + if new_size.width <= img.width: + resize_image(img, new_size.width, None, new_size.quality, luximage.get_image_path_by_size(size)) + else: + raise ValidationError({'items': ["Size is larger than source image"]}) + except ImageSizeError: + print("error creating size") + if new_size.height: + img = Image.open(luximage.image.path) + try: + if new_size.height <= img.height: + resize_image(img, None, new_size.height, new_size.quality, luximage.get_image_path_by_size(size)) + else: + pass + except ImageSizeError: + print("error creating size") diff --git a/app/media/readexif.py b/app/media/readexif.py new file mode 100644 index 0000000..d9e5d70 --- /dev/null +++ b/app/media/readexif.py @@ -0,0 +1,76 @@ +import time +from fractions import Fraction + +from django.contrib.gis.geos import Point + +import exiftool + + +def readexif(image): + """ + takes an image and fills in all the exif data tracked in the image model + + """ + with exiftool.ExifTool() as et: + meta = et.get_metadata(image.image.path) + et.terminate() + image.exif_raw = meta + try: + image.title = meta["EXIF:ImageDescription"] + except: + try: + image.title = meta["XMP:Title"] + except: + pass + try: + image.caption = meta["EXIF:UserComment"] + except: + pass + try: + image.exif_lens = meta["MakerNotes:LensType"] + except: + try: + image.exif_lens = meta["XMP:Lens"] + except: + pass + try: + image.exif_aperture = meta["EXIF:FNumber"] + except: + pass + try: + image.exif_make = meta["EXIF:Make"] + except: + pass + try: + image.exif_model = meta["EXIF:Model"] + except: + pass + try: + image.exif_exposure = str(Fraction(float(meta["EXIF:ExposureTime"])).limit_denominator()) + except: + pass + try: + image.exif_iso = meta["EXIF:ISO"] + except: + pass + try: + image.exif_focal_length = meta["EXIF:FocalLength"] + except: + pass + try: + fmt_date = time.strptime(meta["EXIF:DateTimeOriginal"], "%Y:%m:%d %H:%M:%S") + except: + pass + try: + image.exif_date = time.strftime("%Y-%m-%d %H:%M:%S", fmt_date) + except: + pass + try: + image.height = meta["File:ImageHeight"] + except: + pass + try: + image.width = meta["File:ImageWidth"] + except: + pass + return image diff --git a/app/media/static/image-preview.js b/app/media/static/image-preview.js index b8fead5..c829084 100644 --- a/app/media/static/image-preview.js +++ b/app/media/static/image-preview.js @@ -11,7 +11,7 @@ function build_image_preview () { var img = document.createElement("img"); var request = new XMLHttpRequest(); - request.open('GET', '/photos/luximage/data/admin/preview/'+cur+'/', true); + request.open('GET', '/photos/data/admin/preview/'+cur+'/', true); request.onload = function() { if (request.status >= 200 && request.status < 400) { var data = JSON.parse(request.responseText); diff --git a/app/media/templatetags/get_image_by_size.py b/app/media/templatetags/get_image_by_size.py index c56c44e..a0a62f0 100644 --- a/app/media/templatetags/get_image_by_size.py +++ b/app/media/templatetags/get_image_by_size.py @@ -4,5 +4,5 @@ register = template.Library() @register.simple_tag def get_image_by_size(obj, *args): - method = getattr(obj, "get_image_by_size") + method = getattr(obj, "get_image_url_by_size") return method(*args) diff --git a/app/media/utils.py b/app/media/utils.py index 84e72f5..893663c 100644 --- a/app/media/utils.py +++ b/app/media/utils.py @@ -1,28 +1,26 @@ import os -import re import subprocess -from django.apps import apps -from django.conf import settings - from PIL import ImageFile -from bs4 import BeautifulSoup # pip install python-resize-image from resizeimage import resizeimage -def resize_image(img, width=None, height=None, quality=72, base_path="", filename=""): +def resize_image(img, width=None, height=None, quality=72, filepath=""): + """ + given an image object, size, and filepath + resize the image, then save it , size, and filepath + resize the image, then save it at the filepath + """ + base_path = os.path.dirname(filepath) + if not os.path.isdir(base_path): + os.makedirs(base_path) if width and height: newimg = resizeimage.resize_cover(img, [width, height]) if width and not height: newimg = resizeimage.resize_width(img, width) if height and not width: newimg = resizeimage.resize_height(img, height) - if not os.path.isdir(base_path): - os.makedirs(base_path) - path = "%s%s" % (base_path, filename) ImageFile.MAXBLOCK = img.size[0] * img.size[1] * 4 - newimg.save(path, newimg.format, quality=quality) - subprocess.call(["jpegoptim", "%s" % path]) - - + newimg.save(filepath, newimg.format, quality=quality) + subprocess.call(["jpegoptim", "%s" % filepath]) diff --git a/app/media/views.py b/app/media/views.py index 915b022..04ac11c 100644 --- a/app/media/views.py +++ b/app/media/views.py @@ -1,10 +1,10 @@ import json -from django.shortcuts import render_to_response, render +from django.shortcuts import render from django.template import RequestContext from django.http import Http404, HttpResponse from django.core import serializers -from .models import Photo, PhotoGallery, LuxGallery, LuxImage +from .models import LuxGallery, LuxImage from locations.models import Country, Region from utils.views import PaginatedListView @@ -52,10 +52,10 @@ class GalleryList(PaginatedListView): class OldGalleryList(PaginatedListView): template_name = 'archives/gallery_list.html' - model = PhotoGallery + model = LuxGallery def get_queryset(self): - return PhotoGallery.objects.filter(is_public=True) + return LuxGallery.objects.filter(is_public=True) def get_context_data(self, **kwargs): # Call the base implementation first to get a context @@ -74,7 +74,7 @@ def gallery_list(request, page): request.page_url = '/photos/%d/' request.page = int(page) context = { - 'object_list': PhotoGallery.objects.all(), + 'object_list': LuxGallery.objects.all(), 'page': page, } return render(request, "archives/photos.html", context) @@ -82,13 +82,13 @@ def gallery_list(request, page): def gallery(request, slug): context = { - 'object': PhotoGallery.objects.get(set_slug=slug) + 'object': LuxGallery.objects.get(set_slug=slug) } - return render_to_response('details/photo_galleries.html', context, context_instance=RequestContext(request)) + return render(request, 'details/photo_galleries.html', context) def photo_json(request, slug): - p = PhotoGallery.objects.filter(set_slug=slug) + p = LuxGallery.objects.filter(set_slug=slug) return HttpResponse(serializers.serialize('json', p), mimetype='application/json') @@ -103,7 +103,7 @@ def photo_preview_json(request, pk): def thumb_preview_json(request, pk): p = LuxImage.objects.get(pk=pk) data = {} - data['url'] = p.get_admin_insert() + data['url'] = p.get_image_url_by_size('tn') data = json.dumps(data) return HttpResponse(data) @@ -114,10 +114,10 @@ def gallery_list_by_area(request, slug, page): request.page = int(page) try: region = Region.objects.get(slug__exact=slug) - qs = PhotoGallery.objects.filter(region=region).order_by('-id') + qs = LuxGallery.objects.filter(region=region).order_by('-id') except: region = Country.objects.get(slug__exact=slug) - qs = PhotoGallery.objects.filter(location__state__country=region).order_by('-id') + qs = LuxGallery.objects.filter(location__state__country=region).order_by('-id') if not region: raise Http404 context = { @@ -127,4 +127,4 @@ def gallery_list_by_area(request, slug, page): 'region': region, 'page': page } - return render_to_response("archives/photos.html", context, context_instance=RequestContext(request)) + return render(request, "archives/photos.html", context) |