Skip to content

Commit

Permalink
feat: add option to convert progressive JPEG to baseline
Browse files Browse the repository at this point in the history
  • Loading branch information
desbma committed Jul 11, 2023
1 parent a1a8084 commit 836a1ae
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 4 deletions.
9 changes: 9 additions & 0 deletions sacad/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ async def search_and_download(
amazon_tlds: Sequence[str] = (),
source_classes: Optional[Sequence[Any]] = None,
preserve_format: bool = False,
convert_progressive_jpeg: bool = False,
) -> bool:
"""Search and download a cover, return True if success, False instead."""
logger = logging.getLogger("Main")
Expand Down Expand Up @@ -100,6 +101,7 @@ async def search_and_download(
size_tolerance_prct,
out_filepath,
preserve_format=preserve_format,
convert_progressive_jpeg=convert_progressive_jpeg,
)
except Exception as e:
logger.warning(f"Download of {result} failed: {e.__class__.__qualname__} {e}")
Expand Down Expand Up @@ -153,6 +155,12 @@ def setup_common_args(arg_parser: argparse.ArgumentParser) -> None:
default=False,
help="Preserve source image format if possible. Target format will still be prefered when sorting results.",
)
arg_parser.add_argument(
"--convert-progressive-jpeg",
action="store_true",
default=False,
help="Convert progressive JPEG to baseline if needed. May result in bigger files and loss of quality.",
)


def cl_main() -> None:
Expand Down Expand Up @@ -222,6 +230,7 @@ def cl_main() -> None:
amazon_tlds=args.amazon_tlds,
source_classes=args.cover_sources,
preserve_format=args.preserve_format,
convert_progressive_jpeg=args.convert_progressive_jpeg,
)
future = asyncio.ensure_future(coroutine)
asyncio.get_event_loop().run_until_complete(future)
Expand Down
30 changes: 27 additions & 3 deletions sacad/cover.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import pickle
import shutil
import urllib.parse
from typing import Dict

import appdirs
import bitarray
Expand Down Expand Up @@ -166,13 +167,22 @@ def __str__(self):
s += f" [x{len(self.urls)}]"
return s

async def get(self, target_format, target_size, size_tolerance_prct, out_filepath, *, preserve_format=False):
async def get(
self,
target_format: CoverImageFormat,
target_size: int,
size_tolerance_prct: float,
out_filepath: str,
*,
preserve_format: bool = False,
convert_progressive_jpeg: bool = False,
) -> None:
"""Download cover and process it."""
images_data = []
for i, url in enumerate(self.urls):
# download
logging.getLogger("Cover").info(f"Downloading cover {url!r} (part {i + 1}/{len(self.urls)})...")
headers = {}
headers: Dict[str, str] = {}
self.source.updateHttpHeaders(headers)

async def pre_cache_callback(img_data):
Expand All @@ -193,7 +203,11 @@ async def pre_cache_callback(img_data):
abs(max(self.size) - target_size) > target_size * size_tolerance_prct / 100
)
need_join = len(images_data) > 1
if (need_format_change and (not preserve_format)) or need_join or need_size_change:
need_post_process = (need_format_change and (not preserve_format)) or need_join or need_size_change
need_post_process = need_post_process or (
__class__.isProgressiveJpegData(images_data[0]) and convert_progressive_jpeg
)
if need_post_process:
# post process
image_data = self.postProcess(
images_data, target_format if need_format_change else None, target_size if need_size_change else None
Expand All @@ -213,6 +227,16 @@ async def pre_cache_callback(img_data):
with open(out_filepath, "wb") as file:
file.write(image_data)

@staticmethod
def isProgressiveJpegData(data: bytes) -> bool:
"""Return True if data is from a progressive JPEG."""
in_bytes = io.BytesIO(data)
try:
img = PIL.Image.open(in_bytes)
return bool(img.info["progressive"])
except Exception:
return False

def postProcess(self, images_data, new_format, new_size):
"""
Convert image binary data.
Expand Down
2 changes: 1 addition & 1 deletion sacad/recurse.py
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,6 @@ def ichunk(iterable, n):
def get_covers(work, args):
"""Get missing covers."""
with contextlib.ExitStack() as cm:

if args.cover_pattern == EMBEDDED_ALBUM_ART_SYMBOL:
tmp_prefix = f"{os.path.splitext(os.path.basename(inspect.getfile(inspect.currentframe())))[0]}_"
tmp_dir = cm.enter_context(tempfile.TemporaryDirectory(prefix=tmp_prefix))
Expand Down Expand Up @@ -361,6 +360,7 @@ def post_download(future):
amazon_tlds=args.amazon_tlds,
source_classes=args.cover_sources,
preserve_format=args.preserve_format,
convert_progressive_jpeg=args.convert_progressive_jpeg,
)
future = asyncio.ensure_future(coroutine)
futures[future] = cur_work
Expand Down

0 comments on commit 836a1ae

Please sign in to comment.