Last active
June 20, 2026 15:08
-
-
Save CatTrinket/46091482961dcbff84f9d2f2348cea87 to your computer and use it in GitHub Desktop.
Script to rip images from CARDPVR.PAC from Magic: the Gathering for the Dreamcast
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import os | |
| import os.path | |
| import struct | |
| import sys | |
| import zlib | |
| import pvr2image | |
| def rip_cards(pac, outdir): | |
| assert pac.read(4) == b'PAC\x00' | |
| (card_count,) = struct.unpack('<L', pac.read(4)) | |
| # Includes one extra offset for the end of the last file | |
| offsets = [ | |
| offset for (offset,) in | |
| struct.iter_unpack('<L', pac.read(4 * (card_count + 1))) | |
| ] | |
| temp_pvr_path = os.path.join(outdir, 'temp.pvr') | |
| temp_png_path = os.path.join(outdir, 'temp_png') | |
| for (i, (start, end)) in enumerate(zip(offsets, offsets[1:])): | |
| pac.seek(start) | |
| assert pac.read(4) == b'NZIP' | |
| (decompressed_length,) = struct.unpack('<L', pac.read(4)) | |
| nzip = pac.read(end - start - 8) | |
| pvr = zlib.decompress(nzip, -15) | |
| assert len(pvr) == decompressed_length | |
| with open(temp_pvr_path, 'wb') as temp_pvr: | |
| temp_pvr.write(pvr) | |
| # pvr2image hardcodes \ as dir separator, whereas Linux will just treat | |
| # that as part of the target filename. The following *should* work | |
| # either way, but I've only tested it on Linux. | |
| pvr2image.decode([temp_pvr_path], 'png', temp_png_path, '') | |
| os.rename( | |
| rf'{temp_png_path}\temp.png', | |
| os.path.join(outdir, f'{i}.png') | |
| ) | |
| os.remove(temp_pvr_path) | |
| def main(): | |
| if len(sys.argv) != 3: | |
| exit( | |
| f'Usage: {sys.argv[0]} CARDPVR.PAC outdir\n' | |
| 'Requires pvr2image from PyPI' | |
| ) | |
| with open(sys.argv[1], 'rb') as cardpvr_pac: | |
| rip_cards(cardpvr_pac, sys.argv[2]) | |
| if __name__ == '__main__': | |
| main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment