Initial commit!
This commit is contained in:
138
images/models.py
Normal file
138
images/models.py
Normal file
@@ -0,0 +1,138 @@
|
||||
import uuid
|
||||
from io import BytesIO
|
||||
|
||||
from django.db import models
|
||||
from django.utils import timezone
|
||||
|
||||
from images.utils import get_b2_resource
|
||||
from PIL import Image as PILImage, ImageOps
|
||||
|
||||
|
||||
class Image(models.Model):
|
||||
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
|
||||
creation_date = models.DateTimeField(default=timezone.now)
|
||||
uploaded = models.BooleanField(default=False)
|
||||
original_name = models.CharField(max_length=150)
|
||||
original_mime_type = models.CharField(max_length=10)
|
||||
original_md5 = models.CharField(max_length=32)
|
||||
is_webp_available = models.BooleanField(default=False)
|
||||
is_avif_available = models.BooleanField(default=False)
|
||||
is_jpegli_available = models.BooleanField(default=False)
|
||||
model_version = models.IntegerField(default=1)
|
||||
height = models.IntegerField(default=0)
|
||||
width = models.IntegerField(default=0)
|
||||
|
||||
@property
|
||||
def thumbnail_size(self):
|
||||
if self.height > self.width:
|
||||
return int(600 * self.width / self.height), 600
|
||||
else:
|
||||
return 600, int(600 * self.height / self.width)
|
||||
|
||||
@property
|
||||
def backblaze_filepath(self):
|
||||
return f"{self.id.hex[:2]}/{self.id.hex[2:4]}/{self.id.hex}"
|
||||
|
||||
def create_variant_tasks(self, width, height, original_file_type):
|
||||
ImageVariantTask(
|
||||
image=self,
|
||||
height=height,
|
||||
width=width,
|
||||
original_file_type=original_file_type,
|
||||
file_type="avif",
|
||||
).save()
|
||||
|
||||
ImageVariantTask(
|
||||
image=self,
|
||||
height=height,
|
||||
width=width,
|
||||
original_file_type=original_file_type,
|
||||
file_type="webp",
|
||||
).save()
|
||||
|
||||
ImageVariantTask(
|
||||
image=self,
|
||||
height=height,
|
||||
width=width,
|
||||
original_file_type=original_file_type,
|
||||
file_type="jpegli",
|
||||
).save()
|
||||
|
||||
def create_variant(self, width, height):
|
||||
bucket = get_b2_resource()
|
||||
|
||||
original_image = BytesIO()
|
||||
original_variant = self.imagevariant_set.filter(
|
||||
is_full_size=True, file_type__in=["jpg", "png"]
|
||||
).first()
|
||||
bucket.download_fileobj(
|
||||
f"{self.backblaze_filepath}/{original_variant.width}-{original_variant.height}/image.{original_variant.file_type}",
|
||||
original_image,
|
||||
)
|
||||
original_image.seek(0)
|
||||
|
||||
resized_image = BytesIO()
|
||||
|
||||
file_extension = "jpg"
|
||||
|
||||
with PILImage.open(original_image) as im:
|
||||
ImageOps.exif_transpose(im, in_place=True)
|
||||
im.thumbnail((width, height))
|
||||
|
||||
if im.has_transparency_data:
|
||||
try:
|
||||
im.save(resized_image, "PNG")
|
||||
file_extension = "png"
|
||||
except OSError:
|
||||
im.convert("RGB").save(resized_image, "JPEG")
|
||||
else:
|
||||
try:
|
||||
im.save(resized_image, "JPEG")
|
||||
except OSError:
|
||||
im.convert("RGB").save(resized_image, "JPEG")
|
||||
|
||||
resized_image.seek(0)
|
||||
|
||||
bucket.upload_fileobj(
|
||||
resized_image,
|
||||
f"{self.backblaze_filepath}/{width}-{height}/image.{file_extension}",
|
||||
)
|
||||
|
||||
image_variant = ImageVariant(
|
||||
image=self,
|
||||
height=height,
|
||||
width=width,
|
||||
is_full_size=False,
|
||||
file_type=file_extension,
|
||||
)
|
||||
|
||||
image_variant.save()
|
||||
|
||||
self.create_variant_tasks(width, height, file_extension)
|
||||
|
||||
return image_variant
|
||||
|
||||
|
||||
class ImageVariant(models.Model):
|
||||
image = models.ForeignKey(Image, on_delete=models.CASCADE)
|
||||
height = models.IntegerField()
|
||||
width = models.IntegerField()
|
||||
is_full_size = models.BooleanField(default=False)
|
||||
file_type = models.CharField(max_length=10)
|
||||
|
||||
|
||||
class ImageVariantTask(models.Model):
|
||||
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
image = models.ForeignKey(Image, on_delete=models.CASCADE)
|
||||
height = models.IntegerField()
|
||||
width = models.IntegerField()
|
||||
original_file_type = models.CharField(max_length=10)
|
||||
file_type = models.CharField(max_length=10)
|
||||
|
||||
|
||||
class AuthorizationKey(models.Model):
|
||||
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
|
||||
name = models.CharField(max_length=150)
|
||||
can_upload_image = models.BooleanField(default=False)
|
||||
can_upload_variant = models.BooleanField(default=False)
|
Reference in New Issue
Block a user