Skip to content

Commit

Permalink
Merge pull request #2467 from DemocracyClub/fix-rgba-emblems
Browse files Browse the repository at this point in the history
Remove alpha from emblems when importing from the EC
  • Loading branch information
symroe authored Nov 12, 2024
2 parents 1b15bb4 + 39beabc commit 219f6db
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 1 deletion.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions ynr/apps/moderation_queue/tests/paths.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
BROKEN_IMAGE_FILENAME = abspath(
join(dirname(__file__), "broke-image-example.htm")
)
IMAGE_WITH_ALPHA = abspath(join(dirname(__file__), "image-with-alpha.png"))

ROTATED_IMAGE_FILENAME = abspath(
join(dirname(__file__), "rotated_photo_with_exif.jpg")
Expand Down
25 changes: 24 additions & 1 deletion ynr/apps/parties/importer.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from candidates.models.popolo_extra import UnsafeToDelete
from django.contrib.admin.utils import NestedObjects
from django.db import connection
from PIL import Image

from .constants import (
CORRECTED_DESCRIPTION_DATES,
Expand Down Expand Up @@ -422,6 +423,26 @@ def download_emblem(self):
f.write(r.content)
return ntf.name

def clean_image(self, image_file_name):
# Normalize the image: Sometimes the EC publishes png images with an
# alpha channel. This breaks later conversion to JPEG.
# See: https://github.com/jazzband/sorl-thumbnail/issues/564
with Image.open(image_file_name) as img:
# Convert RGBA to RGB
if img.mode == "RGBA":
# Create a white background and paste the image onto it
background = Image.new("RGB", img.size, (255, 255, 255))
background.paste(img, mask=img.split()[3])
img = background
# LA is luminance + alpha. e.g. greyscale with transparency
if img.mode == "LA":
img = img.convert("L")
# Save the image as a PNG without alpha
png_tempfile = NamedTemporaryFile(delete=False, suffix=".png")
img.save(png_tempfile.name, "PNG")

return png_tempfile.name

def save(self):
existing_emblem = PartyEmblem.objects.filter(
ec_emblem_id=self.emblem_dict["Id"], party=self.party
Expand All @@ -442,6 +463,7 @@ def save(self):
if not mime_type.startswith("image/"):
# This isn't an image, so let's not try to save it
return None
cleaned_image_file_name = self.clean_image(image_file_name)
extension = mimetypes.guess_extension(mime_type)
filename = "Emblem_{}{}".format(self.emblem_dict["Id"], extension)

Expand All @@ -454,9 +476,10 @@ def save(self):
},
)

with open(image_file_name, "rb") as f:
with open(cleaned_image_file_name, "rb") as f:
emblem.image.save(filename, f)
os.remove(image_file_name)
os.remove(cleaned_image_file_name)
return (emblem, True)

def get_default(self):
Expand Down
24 changes: 24 additions & 0 deletions ynr/apps/parties/tests/test_importer.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
Test some of the basic model use cases
"""

from io import StringIO
from tempfile import NamedTemporaryFile

Expand All @@ -12,11 +13,13 @@
from moderation_queue.tests.paths import (
BROKEN_IMAGE_FILENAME,
EXAMPLE_IMAGE_FILENAME,
IMAGE_WITH_ALPHA,
)
from parties.importer import ECParty, ECPartyImporter, make_description_text
from parties.management.commands.parties_import_from_ec import Command
from parties.models import Party, PartyDescription, PartyEmblem
from parties.tests.fixtures import DefaultPartyFixtures
from sorl.thumbnail import get_thumbnail

from .factories import PartyDescriptionFactory, PartyEmblemFactory, PartyFactory

Expand Down Expand Up @@ -355,3 +358,24 @@ def test_create_joint_parties(self):
"joint-party:1-2",
)
self.assertTrue(len(importer.collector), 3)

@patch("parties.importer.ECEmblem.download_emblem")
def test_save_with_alpha_emblem(self, FakeEmblemPath):
"""
As per https://github.com/jazzband/sorl-thumbnail/issues/564
sorl.thumbnail has a bug that means it tries to convert images with an
alpha channel to JPEG. That's not possible in the JPEG format, so we
get a 500 when trying to load the image.
To fix this, remove the alpha channel before saving it at import time.
"""
FakeEmblemPath.return_value = make_tmp_file_from_source(
IMAGE_WITH_ALPHA
)
self.assertFalse(PartyEmblem.objects.all().exists())
party = ECParty(FAKE_PARTY_DICT)
party_obj, _ = party.save()
self.assertTrue(PartyEmblem.objects.all().exists())
get_thumbnail(party_obj.emblems.first().image.file.name, "1x1")

0 comments on commit 219f6db

Please sign in to comment.