I have a Django model like:
class Website(models.Model):
favicon = models.ImageField(
null=False,
blank=True,
default="",
width_field="favicon_width",
height_field="favicon_height",
)
favicon_width = models.PositiveSmallIntegerField(null=True, blank=True)
favicon_height = models.PositiveSmallIntegerField(null=True, blank=True)
I'm fetching a .ico
file and saving it to the favicon
field as a .png
like this:
import io
import requests
from django.core import files
from .models import Website
website = Website.objects.get(pk=1)
response = requests.get("https://www.blogger.com/favicon.ico", stream=True)
image_data = io.BytesIO(response.content)
website.favicon.save("favicon.png", files.File(image_data))
Behind the scenes, Pillow successfully converts the ICO file to a PNG, and saves the file. But I then get an error. The traceback includes:
# More here
File /usr/local/lib/python3.10/site-packages/django/db/models/fields/files.py:491, in ImageField.update_dimension_fields(self, instance, force, *args, **kwargs)
489 # file should be an instance of ImageFieldFile or should be None.
490 if file:
--> 491 width = file.width
492 height = file.height
493 else:
494 # No file, so clear dimensions fields.
# Lots more here
File /usr/local/lib/python3.10/site-packages/PIL/Image.py:804, in Image.frombytes(self, data, decoder_name, *args)
802 if s[0] >= 0:
803 msg = "not enough image data"
--> 804 raise ValueError(msg)
805 if s[1] != 0:
806 msg = "cannot decode image data"
ValueError: not enough image data
So it can save the image but, I'm guessing, not get the width/height from the image to save.
BUT, some ICO files (like https://thoughts.hnr.fyi/images/favicon.ico
) work fine.
It took a lot of trial and error, but this seems to work:
import io
import requests
from django.core.files.base import ContentFile
from .models import Website
website = Website.objects.get(pk=1)
response = requests.get("https://www.blogger.com/favicon.ico", stream=True)
img = Image.open(io.BytesIO(response.content))
# Convert image to a PNG
buffer = io.BytesIO()
img.save(fp=buffer, format="PNG")
website.favicon.save("favicon.png", ContentFile(buffer.getvalue()))