ps1: embed real game art (ICON0 + PIC1) in converted EBOOTs
Fetch the game's cover art (libretro / ScreenScraper / IGDB / Wikipedia, reusing the local cover cache) and bake it into the EBOOT's ICON0 (144x80 XMB icon) and PIC1 (480x272 launch background) instead of the default PS1 icon. Best-effort: falls back to the base icon/empty background when no art is found. convert()/convert_to_folder() gain optional icon0/pic1 params.
This commit is contained in:
@@ -808,6 +808,71 @@ def compose_game_cover(key_art_bytes):
|
||||
return bytes(ba)
|
||||
|
||||
|
||||
def make_ps1_assets(cover_bytes):
|
||||
"""Build ICON0.PNG (144x80) and PIC1.PNG (480x272) from PS1 cover art.
|
||||
|
||||
Returns ``(icon0_bytes, pic1_bytes)``, or ``(None, None)`` when the art
|
||||
can't be decoded (or Qt isn't available). ICON0 is the art letterboxed
|
||||
inside the icon frame; PIC1 is the art cropped to fill the launch
|
||||
background.
|
||||
"""
|
||||
try:
|
||||
from PySide6.QtCore import QBuffer, QByteArray, Qt
|
||||
from PySide6.QtGui import QImage, QPainter
|
||||
except Exception: # noqa: BLE001 - headless API may lack PySide6
|
||||
return None, None
|
||||
|
||||
art = QImage.fromData(cover_bytes)
|
||||
if art.isNull():
|
||||
return None, None
|
||||
art = art.convertToFormat(QImage.Format_ARGB32)
|
||||
|
||||
def _save(img):
|
||||
ba = QByteArray()
|
||||
buf = QBuffer(ba)
|
||||
buf.open(QBuffer.WriteOnly)
|
||||
img.save(buf, "PNG")
|
||||
buf.close()
|
||||
return bytes(ba)
|
||||
|
||||
# ICON0: fit the cover inside 144x80 (transparent margins).
|
||||
icon = QImage(144, 80, QImage.Format_ARGB32)
|
||||
icon.fill(Qt.transparent)
|
||||
p = QPainter(icon)
|
||||
scaled = art.scaled(144, 80, Qt.KeepAspectRatio, Qt.SmoothTransformation)
|
||||
p.drawImage((144 - scaled.width()) // 2, (80 - scaled.height()) // 2, scaled)
|
||||
p.end()
|
||||
|
||||
# PIC1: crop the cover to fill 480x272.
|
||||
pic = QImage(480, 272, QImage.Format_ARGB32)
|
||||
pic.fill(Qt.transparent)
|
||||
p = QPainter(pic)
|
||||
scaled = art.scaled(480, 272, Qt.KeepAspectRatioByExpanding, Qt.SmoothTransformation)
|
||||
p.drawImage((480 - scaled.width()) // 2, (272 - scaled.height()) // 2, scaled)
|
||||
p.end()
|
||||
|
||||
return _save(icon), _save(pic)
|
||||
|
||||
|
||||
def ps1_art(title, release_id, timeout=10):
|
||||
"""Fetch a PS1 game's cover and return ``(icon0, pic1)`` PNG bytes.
|
||||
|
||||
Reuses the local cover cache when available, otherwise searches the PS1
|
||||
sources (libretro, ScreenScraper, IGDB, Wikipedia). Returns
|
||||
``(None, None)`` when no art can be produced.
|
||||
"""
|
||||
try:
|
||||
path = fetch_cover(title, release_id, "ps1", timeout=timeout)
|
||||
except Exception: # noqa: BLE001
|
||||
return None, None
|
||||
if path is None:
|
||||
return None, None
|
||||
try:
|
||||
return make_ps1_assets(path.read_bytes())
|
||||
except OSError:
|
||||
return None, None
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------- #
|
||||
# Public entry point
|
||||
# --------------------------------------------------------------------------- #
|
||||
|
||||
Reference in New Issue
Block a user