123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124 |
- from io import BytesIO
- from PIL import Image
- from django import forms
- from django.core.files.base import ContentFile
- from django.utils.translation import gettext_lazy as _
- from ...core.utils import get_file_hash
- from ...core.validators import validate_image_square
- from ..models import Icon
- FAVICON_MIN_SIZE = 48
- FAVICON_SIZES = ((16, 16), (32, 32), (48, 48))
- APPLE_TOUCH_MIN_SIZE = 180
- VALID_MIME = ("image/gif", "image/jpeg", "image/png")
- class IconsForm(forms.Form):
- favicon = forms.ImageField(
- label=_("Upload image"),
- help_text=_("Uploaded image should be a square that is 48px wide and tall."),
- required=False,
- )
- favicon_delete = forms.BooleanField(label=_("Delete custom icon"), required=False)
- apple_touch_icon = forms.ImageField(
- label=_("Upload image"),
- help_text=_("Uploaded image should be square at least 180px wide and tall."),
- required=False,
- )
- apple_touch_icon_delete = forms.BooleanField(
- label=_("Delete custom icon"), required=False
- )
- def clean_favicon(self):
- upload = self.cleaned_data.get("favicon")
- if not upload or upload == self.initial.get("favicon"):
- return None
- validate_image_square(upload.image)
- validate_image_dimensions(upload.image, FAVICON_MIN_SIZE)
- validate_image_mime_type(upload)
- return upload
- def clean_apple_touch_icon(self):
- upload = self.cleaned_data.get("apple_touch_icon")
- if not upload or upload == self.initial.get("apple_touch_icon"):
- return None
- validate_image_square(upload.image)
- validate_image_dimensions(upload.image, APPLE_TOUCH_MIN_SIZE)
- validate_image_mime_type(upload)
- return upload
- def save(self):
- if self.cleaned_data.get("favicon"):
- self.save_favicon(self.cleaned_data["favicon"])
- elif self.cleaned_data.get("favicon_delete"):
- self.delete_icons(Icon.FAVICON_TYPES)
- if self.cleaned_data.get("apple_touch_icon"):
- self.save_apple_touch_icon(self.cleaned_data["apple_touch_icon"])
- elif self.cleaned_data.get("apple_touch_icon_delete"):
- self.delete_icons([Icon.TYPE_APPLE_TOUCH_ICON])
- def save_favicon(self, image):
- self.delete_icons(Icon.FAVICON_TYPES)
- save_favicon(image)
- save_icon(image, (32, 32), Icon.TYPE_FAVICON_32)
- save_icon(image, (16, 16), Icon.TYPE_FAVICON_16)
- def save_apple_touch_icon(self, image):
- self.delete_icons([Icon.TYPE_APPLE_TOUCH_ICON])
- save_icon(image, (180, 180), Icon.TYPE_APPLE_TOUCH_ICON)
- def delete_icons(self, icon_types):
- for icon in Icon.objects.filter(type__in=icon_types):
- icon.delete()
- def save_favicon(image):
- icon = Image.open(image)
- buffer = BytesIO()
- icon.save(buffer, "ICO", sizes=FAVICON_SIZES)
- buffer.seek(0)
- icon_file = ContentFile(buffer.read())
- icon_file.name = "%s.%s.ico" % ("favicon", get_file_hash(icon_file))
- Icon.objects.create(type=Icon.TYPE_FAVICON, image=icon_file, size=icon_file.size)
- def save_icon(image, size, icon_type):
- icon = Image.open(image)
- icon.thumbnail(size)
- buffer = BytesIO()
- icon.save(buffer, "PNG")
- buffer.seek(0)
- icon_file = ContentFile(buffer.read())
- icon_file.name = "%s.%s.png" % (
- icon_type.replace("_", "-"),
- get_file_hash(icon_file),
- )
- Icon.objects.create(type=icon_type, image=icon_file, size=icon_file.size)
- def validate_image_dimensions(image, size):
- if image.width < size:
- raise forms.ValidationError(
- _("Uploaded image's edge should be at least %(size)s pixels long.")
- % {"size": size}
- )
- def validate_image_mime_type(upload):
- if upload.content_type not in VALID_MIME:
- raise forms.ValidationError(_("Uploaded image was not gif, jpeg or png."))
|