diff --git a/picard/formats/vorbis.py b/picard/formats/vorbis.py index 3ebf4ee4d..9efa49f4c 100644 --- a/picard/formats/vorbis.py +++ b/picard/formats/vorbis.py @@ -49,6 +49,7 @@ from picard.util import ( ) +FLAC_MAX_BLOCK_SIZE = 2 ** 24 - 1 # FLAC block size is limited to a 24 bit integer INVALID_CHARS = re.compile('([^\x20-\x7d]|=)') @@ -271,6 +272,14 @@ class VCommentFile(File): picture.height = image.height picture.type = image_type_as_id3_num(image.maintype) if is_flac: + # See https://xiph.org/flac/format.html#metadata_block_picture + expected_block_size = (8 * 4 + len(picture.data) + + len(picture.mime) + + len(picture.desc.encode('UTF-8'))) + if expected_block_size > FLAC_MAX_BLOCK_SIZE: + log.error('Failed saving image to %r: Image size of %d bytes exceeds maximum FLAC block size of %d bytes', + filename, expected_block_size, FLAC_MAX_BLOCK_SIZE) + continue file.add_picture(picture) else: tags.setdefault("METADATA_BLOCK_PICTURE", []).append( diff --git a/test/formats/test_vorbis.py b/test/formats/test_vorbis.py index 41afe7295..5bc8117c3 100644 --- a/test/formats/test_vorbis.py +++ b/test/formats/test_vorbis.py @@ -10,7 +10,10 @@ from mutagen.flac import ( VCFLACDict, ) -from test.picardtestcase import PicardTestCase +from test.picardtestcase import ( + PicardTestCase, + create_fake_png, +) from picard import ( config, @@ -291,6 +294,15 @@ class FlacCoverArtTest(CommonCoverArtTests.CoverArtTestCase): self.assertNotEqual(pic.height, 0) self.assertEqual(pic.height, test.height) + def test_save_large_pics(self): + # 16 MB image + data = create_fake_png(b"a" * 1024 * 1024 * 16) + image = CoverArtImage(data=data) + file_save_image(self.filename, image) + raw_metadata = load_raw(self.filename) + # Images with more than 16 MB cannot be saved to FLAC + self.assertEqual(0, len(raw_metadata.pictures)) + class OggAudioVideoFileTest(PicardTestCase): def test_ogg_audio(self):