"""Orchestrate: converted image -> self-contained viewer -> Commodore disk image.""" from __future__ import annotations import os from . import basicgen, crt, diskimage, imginfo from .convert.base import Conversion from .viewer.assemble import (SOURCES, build_cart_rom, build_data_prg, build_viewer_prg) def export_disk(conv: Conversion, output_path: str, disk_format: str | None = None, disk_name: str | None = None, include_graphic_file: bool = True, source_path: str | None = None, video: str = "pal", display: str = "key", seconds: int = 0, layout: str = "unified") -> str: """Write ``conv`` to a disk image at ``output_path``. The disk's first (bootable) file is a self-contained viewer that already embeds the picture, so ``LOAD"*",8,1`` then ``RUN`` displays it. When ``include_graphic_file`` is set, the picture is also written in a standard interchange format (e.g. Koala) for use in other C64 art tools. When ``source_path`` is given and there is room, a colourful BASIC "info" program describing the original image is added too. Returns the absolute path written. """ fmt = diskimage.fmt_from_path(output_path, disk_format) stem = os.path.splitext(os.path.basename(output_path))[0] name = diskimage.petscii_name(disk_name or stem or "8bitlenser") # Timing-sensitive viewers (FLI) have an NTSC variant; others run on both. vkey = conv.viewer if video == "ntsc" and f"{conv.viewer}_ntsc" in SOURCES: vkey = f"{conv.viewer}_ntsc" # Separate layout (viewer code + a standalone "data" file the viewer loads) is # supported by the simple viewers; FLI/interlace fall back to unified. separate = layout == "separate" and vkey in ("hires", "multicolor") viewer_prg = build_viewer_prg(vkey, conv.data, conv.data_addr, display=display, seconds=seconds, video=video, separate=separate) files: list[tuple[str, bytes]] = [(name, viewer_prg)] if separate: files.append(("data", build_data_prg(conv.data, conv.data_addr))) if include_graphic_file: files.extend(conv.extra_files) if source_path: # Best effort: never let the info file break a successful export. try: info = basicgen.build_info_prg(imginfo.gather(source_path)) budget = diskimage.BLOCKS_FREE[fmt] * 254 info_name = "info" if name != "info" else "picinfo" if sum(len(b) for _, b in files) + len(info) <= budget: files.append((info_name, info)) except Exception: pass return diskimage.build_disk(output_path, fmt, name, "01", files) def export_cart(conv: Conversion, output_path: str, source_path: str | None = None, video: str = "pal", display: str = "forever", seconds: int = 0) -> str: """Write ``conv`` as an autostarting 16K C64 .crt cartridge. Only hires/multicolor/mono fit a 16K cart; FLI/interlace must use a disk.""" if not output_path.lower().endswith(".crt"): output_path += ".crt" name = os.path.splitext(os.path.basename(output_path))[0] rom = build_cart_rom(conv.viewer, conv.data, display=display, seconds=seconds, video=video) return crt.write_crt(rom, output_path, name)