Cover-Embedding: Auflösung auf 500px reduzieren vor dem Einbetten
Neue Hilfsfunktion _scale_cover_for_embed() skaliert das Coverbild mit Pillow auf max. 500px (EMBED_COVER_MAX_SIZE) und kodiert es als JPEG quality=85 in-memory. embed_cover() liest nicht mehr die rohen Bytes der Originaldatei, sondern nutzt das skalierte Bild. Ergebnis: eingebettete Cover ~40–100 KB statt 200–500 KB des 1200px-Originals, auf HiDPI-Displays noch scharf erkennbar. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
3fa6237f94
commit
256be0ae33
1 changed files with 25 additions and 3 deletions
|
|
@ -2,12 +2,14 @@
|
|||
|
||||
from __future__ import annotations
|
||||
|
||||
import io
|
||||
import logging
|
||||
from pathlib import Path
|
||||
|
||||
from mutagen import File as MutagenFile
|
||||
from mutagen.flac import FLAC, Picture
|
||||
from mutagen.id3 import APIC, ID3
|
||||
from PIL import Image
|
||||
|
||||
from musiksammlung.models import Album, Disc, Track
|
||||
|
||||
|
|
@ -75,11 +77,31 @@ def embed_album_cover(album: Album, album_dir: Path, cover_path: Path) -> None:
|
|||
embed_cover(audio_file, cover_path)
|
||||
|
||||
|
||||
def embed_cover(audio_path: Path, cover_path: Path) -> None:
|
||||
"""Bettet ein Cover-Bild in eine Audiodatei ein."""
|
||||
cover_data = cover_path.read_bytes()
|
||||
mime = "image/jpeg" if cover_path.suffix.lower() in (".jpg", ".jpeg") else "image/png"
|
||||
# Maximale Auflösung für eingebettete Cover (längste Seite in Pixeln).
|
||||
# Kleiner als das gespeicherte Originalbild (1200 px), aber auf HiDPI-Displays
|
||||
# noch scharf genug. Typische Dateigröße: 40–100 KB statt 200–500 KB.
|
||||
EMBED_COVER_MAX_SIZE = 500
|
||||
|
||||
|
||||
def _scale_cover_for_embed(cover_path: Path, max_size: int) -> tuple[bytes, str]:
|
||||
"""Skaliert ein Coverbild für das Einbetten und gibt (bytes, mime) zurück."""
|
||||
img = Image.open(cover_path)
|
||||
if max(img.size) > max_size:
|
||||
img.thumbnail((max_size, max_size), Image.LANCZOS)
|
||||
if img.mode in ("RGBA", "P"):
|
||||
img = img.convert("RGB")
|
||||
buf = io.BytesIO()
|
||||
img.save(buf, "JPEG", quality=85)
|
||||
return buf.getvalue(), "image/jpeg"
|
||||
|
||||
|
||||
def embed_cover(audio_path: Path, cover_path: Path) -> None:
|
||||
"""Bettet ein Cover-Bild in eine Audiodatei ein.
|
||||
|
||||
Das Bild wird auf EMBED_COVER_MAX_SIZE herunterskaliert, damit die
|
||||
eingebetteten Cover die Audiodateigröße nicht wesentlich vergrößern.
|
||||
"""
|
||||
cover_data, mime = _scale_cover_for_embed(cover_path, EMBED_COVER_MAX_SIZE)
|
||||
suffix = audio_path.suffix.lower()
|
||||
|
||||
if suffix == ".flac":
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue