Skip to main content

Load images from 8-bit computer tapes

Project description

pillow_zx_spectrum

Jetpac Treasure Island Dizzy Daley Thompson's Decathlon Jet Set Willy II

Pillow loaders for ZX Spectrum loading screens, extracted from tape, disk and snapshot files in the wild.

Open a tape, disk image, or snapshot with Image.open(...) and Pillow gives you a 256×192 RGB image with the original Spectrum colours. Files that contain multiple screens (multi-load games, multi-side disks) expose them as Pillow frames via seek() / n_frames.

Install

pip install pillow_zx_spectrum

Usage

from PIL import Image
import pillow_zx_spectrum  # registers the plugins on import

img = Image.open("Glug Glug (1984)(CRL).tap")
img.save("loading-screen.png")
print(img.size)                   # (256, 192)
print(img.info["pixel_aspect_ratio"])  # (1, 1)

Multi-screen containers (disks, multi-load tapes) expose every screen they hold. Iterate with the stock Pillow helper:

from PIL import ImageSequence

img = Image.open("Moonwalker (Erbe).dsk")
print(img.n_frames)  # e.g. 2
for i, frame in enumerate(ImageSequence.Iterator(img)):
    frame.save(f"moonwalker.{i}.png")

Supported formats

Tape

Ext Format Notes
.tap TAP Plain ROM-loader block stream
.tzx TZX Versioned tape with timing/meta blocks; we extract from standard (0x10) and turbo-speed (0x11) data blocks. Custom-loader pure-data blocks (SpeedLock / BleepLoad / Alkatraz, block 0x14) are skipped — they need per-protection decoders.
.scr SCREEN$ Raw 6912-byte screen dump

Disk

Ext Format Notes
.dsk CPC DSK Spectrum +3 / Amstrad CPC, both standard and "Extended" variants. CP/M file system parsed (handles fragmented allocation). Auto-detects single/double-sided and various reserved-track conventions.
.scl TR-DOS packed "SINCLAIR" magic, compact distribution format used in Russian-speaking scene
.trd TR-DOS raw Sector-by-sector TR-DOS floppy dump; tolerant of truncated images
.mgt DISCiPLE / +D Side-interleaved 80-track disk for the MGT DISCiPLE & +D interfaces. CODE/SCREEN$ files reassembled by following the per-sector chain.
.d40, .d80 Didaktik MDOS Czechoslovak Didaktik D40/D80 floppy. MDOS file system with non-standard FAT12 packing (the 12-bit entries' high nibbles are byte-swapped relative to MS FAT12). Auto-detects geometry from the boot sector "SDOS" marker. Most TOSEC Czech games use packed loaders so plain SCREEN$ extraction is rare.

Microdrive

Ext Format Notes
.mdr Microdrive cart Sector-by-sector dump of a Spectrum Microdrive cartridge (543-byte sectors with mod-255 checksums). Files reconstructed by gathering all records belonging to a filename and stripping the inline 9-byte header. PRINT# files are not handled.

Snapshot

Ext Format Notes
.sna SNA Classic 48K (49179 bytes) / 128K (131103 bytes) snapshot
.z80 Z80 Gerton Lunter format (v1, v2, v3); 48K and 128K with bank decompression
.szx SZX / ZX-State Spectaculator's modern chunked snapshot, with zlib-compressed RAM pages
.slt SLT "Super Level Loader" — a Z80 snapshot with a table of additional screens (each becomes a frame)

For 128K snapshots the shadow screen (bank 7) is exposed as an extra frame when it's distinct from the main screen.

How it works

Every container is reduced to a sequence of load events(addr, body, name, kind) tuples — and walked into a 64K Spectrum RAM image. After each write the pipeline harvests two kinds of candidate:

  1. Direct — if the event's body is exactly 6912 bytes (the SCREEN$ shape), it might be a screen, regardless of its load address.
  2. RAM snapshot — slice $4000-$5AFF after the write and emit it if the screen area now contains a new picture (catches screens loaded as part of larger CODE blocks, screens overwritten by later loads, etc.)

Candidates are then ranked by filename hint (SCR / PIC / TITL / LOAD / INTRO...) → canonical $4000 address → other; bodies that clearly aren't screens (random attribute distribution, all-FLASH cells) are dropped. The same pipeline runs for every format.

What we don't load

  • Sampled-audio tapes (.csw, .wav, .mp3) — these encode the loader's pulse train, decoding requires a Z80 emulator running the Spectrum ROM
  • Copy-protected disks (.ipf) — needs the CAPS/SPS library
  • Custom-loader tapes (SpeedLock 7, Alkatraz, BleepLoad, ...) — non-standard timing; the screen lives inside TZX 0x14 pure-data blocks that we skip rather than implement per-protection decoders for
  • 16K Spectrum games — no SCREEN$ saved before the program
  • BASIC-only programs that draw their screen at runtime

These cases produce UnidentifiedImageError ("recognised the format, nothing to extract") rather than a misleading blank frame.

License

WTFPL with one additional clause:

  1. Don't blame me.

Do what you like, but you're to blame.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pillow_zx_spectrum-0.1.0.tar.gz (40.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pillow_zx_spectrum-0.1.0-py3-none-any.whl (54.9 kB view details)

Uploaded Python 3

File details

Details for the file pillow_zx_spectrum-0.1.0.tar.gz.

File metadata

  • Download URL: pillow_zx_spectrum-0.1.0.tar.gz
  • Upload date:
  • Size: 40.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.7

File hashes

Hashes for pillow_zx_spectrum-0.1.0.tar.gz
Algorithm Hash digest
SHA256 832b758a86e677105946202a4be911275214705bfe2a274bbfdd8b6108bb3297
MD5 758213129b5fc54cff0d3fce237627e8
BLAKE2b-256 40cc5028978705e725ed5a5efb43394e2028102643a3b351bce1f0fd5e7bbbad

See more details on using hashes here.

File details

Details for the file pillow_zx_spectrum-0.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for pillow_zx_spectrum-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 fff08b8821444eb419bfaf39d7dd92a761272848ae729a14f2c698147f8055ee
MD5 9b0cd5af0f5fb4b1a2ac0bd86599cf43
BLAKE2b-256 690121720c80478a3b57f8025d8fd7248a7d332c114f450d92432821a83a7df5

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page