diff --git a/picard/coverart/__init__.py b/picard/coverart/__init__.py index e3b4efe6a..adc4e0d71 100644 --- a/picard/coverart/__init__.py +++ b/picard/coverart/__init__.py @@ -60,7 +60,6 @@ class CoverArt: self.metadata = metadata self.release = release # not used in this class, but used by providers self.front_image_found = False - self.previous_images = album.orig_metadata.images.get_types_dict() def __repr__(self): return "%s for %r" % (self.__class__.__name__, self.album) @@ -101,19 +100,6 @@ class CoverArt: except (CoverArtImageIdentificationError, CoverArtProcessingError) as e: self.album.error_append(e) - def _should_save_image(self, coverartimage, data, info): - config = get_config() - if config.setting['dont_replace_with_smaller_cover']: - downloaded_types = coverartimage.normalized_types() - if downloaded_types in self.previous_images: - previous_image = self.previous_images[downloaded_types] - if info.width < previous_image.width or info.height < previous_image.height: - log.debug("Discarding cover art. A bigger image with the same types is already embedded.") - return False - if coverartimage.can_be_filtered: - return run_image_filters(data, info) - return True - def _coverart_downloaded(self, coverartimage, data, http, error): """Handle finished download, save it to metadata""" self.album._requests -= 1 @@ -134,7 +120,10 @@ class CoverArt: ) try: info = imageinfo.identify(data) - if self._should_save_image(coverartimage, data, info): + filters_result = True + if coverartimage.can_be_filtered: + filters_result = run_image_filters(data, info, self.album, coverartimage) + if filters_result: self._set_metadata(coverartimage, data, info) except (CoverArtImageIOError, imageinfo.IdentificationError): # It doesn't make sense to store/download more images if we can't diff --git a/picard/coverart/processing/__init__.py b/picard/coverart/processing/__init__.py index 85f15f451..4847a03c9 100644 --- a/picard/coverart/processing/__init__.py +++ b/picard/coverart/processing/__init__.py @@ -39,9 +39,9 @@ from picard.extension_points.cover_art_processors import ( from picard.util.imageinfo import IdentificationError -def run_image_filters(data, info): +def run_image_filters(data, info, album, coverartimage): for f in ext_point_cover_art_filters: - if not f(data, info): + if not f(data, info, album, coverartimage): return False return True diff --git a/picard/coverart/processing/filters.py b/picard/coverart/processing/filters.py index f6df3c056..c1a8f238d 100644 --- a/picard/coverart/processing/filters.py +++ b/picard/coverart/processing/filters.py @@ -45,7 +45,7 @@ def _check_threshold_size(width, height): return True -def size_filter(data, info): +def size_filter(data, info, album, coverartimage): return _check_threshold_size(info.width, info.height) @@ -55,5 +55,24 @@ def size_metadata_filter(metadata): return _check_threshold_size(metadata['width'], metadata['height']) +def bigger_previous_image_filter(data, info, album, coverartimage): + config = get_config() + if config.setting['dont_replace_with_smaller_cover'] and config.setting['save_images_to_tags']: + downloaded_types = coverartimage.normalized_types() + previous_images = album.orig_metadata.images.get_types_dict() + if downloaded_types in previous_images: + previous_image = previous_images[downloaded_types] + if info.width < previous_image.width or info.height < previous_image.height: + log.debug("Discarding cover art. A bigger image with the same types is already embedded.") + return False + return True + + +def image_types_filter(data, info, album, coverartimage): + return True + + register_cover_art_filter(size_filter) register_cover_art_metadata_filter(size_metadata_filter) +register_cover_art_filter(bigger_previous_image_filter) +register_cover_art_filter(image_types_filter) diff --git a/picard/util/imagelist.py b/picard/util/imagelist.py index dd186312b..d0b3df7cb 100644 --- a/picard/util/imagelist.py +++ b/picard/util/imagelist.py @@ -105,5 +105,10 @@ class ImageList(MutableSequence): def get_types_dict(self): types_dict = dict() for image in self._images: + image_types = image.normalized_types() + if image_types in types_dict: + previous_image = types_dict[image_types] + if image.width > previous_image.width or image.height > previous_image.height: + continue types_dict[image.normalized_types()] = image return types_dict diff --git a/test/test_coverart_processing.py b/test/test_coverart_processing.py index 7dac01bad..a8cdfd87c 100644 --- a/test/test_coverart_processing.py +++ b/test/test_coverart_processing.py @@ -26,10 +26,12 @@ from PyQt6.QtGui import QImage from test.picardtestcase import PicardTestCase from picard import config +from picard.album import Album from picard.const.cover_processing import ResizeModes from picard.coverart.image import CoverArtImage from picard.coverart.processing import run_image_processors from picard.coverart.processing.filters import ( + bigger_previous_image_filter, size_filter, size_metadata_filter, ) @@ -43,6 +45,7 @@ from picard.extension_points.cover_art_processors import ( ProcessingTarget, ) from picard.util import imageinfo +from picard.util.imagelist import ImageList def create_fake_image(width, height, image_format): @@ -64,7 +67,9 @@ class ImageFiltersTest(PicardTestCase): settings = { 'filter_cover_by_size': True, 'cover_minimum_width': 500, - 'cover_minimum_height': 500 + 'cover_minimum_height': 500, + 'dont_replace_with_smaller_cover': True, + 'save_images_to_tags': True, } self.set_config_values(settings) @@ -72,9 +77,9 @@ class ImageFiltersTest(PicardTestCase): image1, info1 = create_fake_image(400, 600, 'png') image2, info2 = create_fake_image(500, 500, 'jpeg') image3, info3 = create_fake_image(600, 600, 'tiff') - self.assertFalse(size_filter(image1, info1)) - self.assertTrue(size_filter(image2, info2)) - self.assertTrue(size_filter(image3, info3)) + self.assertFalse(size_filter(image1, info1, None, None)) + self.assertTrue(size_filter(image2, info2, None, None)) + self.assertTrue(size_filter(image3, info3, None, None)) def test_filter_by_size_metadata(self): image_metadata1 = {'width': 400, 'height': 600} @@ -84,6 +89,20 @@ class ImageFiltersTest(PicardTestCase): self.assertTrue(size_metadata_filter(image_metadata2)) self.assertTrue(size_metadata_filter(image_metadata3)) + def test_filter_by_previous_image_size(self): + previous_coverartimage = CoverArtImage(types=['front'], support_types=True) + previous_coverartimage.width = 1000 + previous_coverartimage.height = 1000 + album = Album(None) + album.orig_metadata.images = ImageList([previous_coverartimage]) + image1, info1 = create_fake_image(500, 500, 'jpg') + image2, info2 = create_fake_image(2000, 2000, 'jpg') + coverartimage = CoverArtImage(types=['front'], support_types=True) + self.assertFalse(bigger_previous_image_filter(image1, info1, album, coverartimage)) + self.assertTrue(bigger_previous_image_filter(image2, info2, album, coverartimage)) + coverartimage = CoverArtImage(types=['back'], support_types=True) + self.assertTrue(bigger_previous_image_filter(image1, info1, album, coverartimage)) + class ImageProcessorsTest(PicardTestCase): def setUp(self):