{"id":25330929,"url":"https://github.com/jifish/elfish-extractor","last_synced_at":"2025-04-08T05:49:52.895Z","repository":{"id":276487320,"uuid":"929435077","full_name":"JiFish/elfish-extractor","owner":"JiFish","description":"A tool for extracting frames from .fsh, .mvy, .aqu and .isb files used by the 1994 El-Fish software.","archived":false,"fork":false,"pushed_at":"2025-02-08T15:01:07.000Z","size":0,"stargazers_count":0,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-02-08T15:31:47.285Z","etag":null,"topics":["el-fish","elfish","maxis","python","reverse-engineering"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/JiFish.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2025-02-08T14:48:16.000Z","updated_at":"2025-02-08T15:01:11.000Z","dependencies_parsed_at":"2025-02-08T15:42:01.701Z","dependency_job_id":null,"html_url":"https://github.com/JiFish/elfish-extractor","commit_stats":null,"previous_names":["jifish/elfish-extractor"],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JiFish%2Felfish-extractor","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JiFish%2Felfish-extractor/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JiFish%2Felfish-extractor/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JiFish%2Felfish-extractor/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/JiFish","download_url":"https://codeload.github.com/JiFish/elfish-extractor/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247785944,"owners_count":20995644,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["el-fish","elfish","maxis","python","reverse-engineering"],"created_at":"2025-02-14T03:56:25.204Z","updated_at":"2025-04-08T05:49:52.870Z","avatar_url":"https://github.com/JiFish.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# El-Fish Extractor\n\nEl-Fish Extractor is a tool for extracting frames from `.fsh`, `.mvy`, `.aqu` and `.isb` files used by the 1994 El-Fish software. It reads the input file, extracts the frames, and saves them as images in the specified output directory.\n\nThis is based on the work of Vidar Holen: https://www.vidarholen.net/contents/elfish/\n\nI ported the java tool to python in the hopes that after doing so, I'd understand enough of the file format to write something that can pack the frames back in to the file. This would be the holy grail for El-Fish: the ability to create new animated objects. The first new feature for El-Fish in over 30 years! However, I wasn't able to crack it. This repo is provided in the hope that somebody else can solve this.\n\nFor posterity, I included Vidar's information on the file-format at the bottom of this file.\n\n## Requirements\n\n- Python 3.x\n- Pillow library\n\n## Installation\n\n1. Clone the repository:\n    ```sh\n    git clone https://github.com/jifish/elfish-extractor.git\n    ```\n2. Install the required dependencies:\n    ```sh\n    pip install -r requirements.txt\n    ```\n\n## Usage\n\nTo use the Elfish Extractor, run the following command:\n\n```sh\npython extract.py \u003cinput_file\u003e \u003coutput_dir\u003e\n```\n\n- `\u003cinput_file\u003e`: Path to the `.fsh`, `.mvy`, `.aqu` or `.isb` file.\n- `\u003coutput_dir\u003e`: Directory where the extracted frames will be saved.\n\n### Example\n\n```sh\npython extract.py example.fsh output/\n```\n\nThis command will extract frames from `example.fsh` and save them in the `output/` directory.\n\n### Example Output\n\n![Example Output](example_output.jpg)\n\n## File Format information\n\nEach file is encoded in streams, each stream has a number of frames. All integers are little-endian.\n\n```\n8 bytes   Unknown (magic?)\n2 bytes   Unknown (zero)\n\n--(offset now 0A)--\n8 bytes   Fish name, zero-padded at end.\n4 bytes   Unknown (zero)\n2 bytes   Unknown (rendering progress?)\n2 bytes   Unknown (rendering total?)\n2 bytes   Unknown (Total number of animation frames + 7 ?)\n4 bytes   Unknown\n\n--(offset now 20)--\n4 bytes   Total file length\n103 bytes Unknown\n\n--(offset now 8B)--\n4 bytes   Stream offset - Detailed frame\n4 bytes   Stream offset - Icon frame\n4 bytes   Stream offset - Animation frames\n\nEach stream is a linked list of frames. Each frame has a 30 byte header:\n\n4 bytes   Frame length (from start of header)\n4 bytes   Frame number\n4 bytes   Previous entry (absolute seek), or 0 if first frame in the series\n4 bytes   Next entry (absolute seek), or 0 if last frame in the series\n4 bytes   Unknown (same as frame length)\n2 bytes   Unknown (movement increment?)\n2 bytes   X offset (?)\n2 bytes   Y offset (?)\n2 bytes   Frame width\n2 bytes   Frame height\n\nThen follows frame data. Each frame is encoded in lines, each line is built up from plot sections. Each plot section has a length, position, and pixels:\n\n      2 bytes      2 bytes     'Length' bytes\n  [ Data length  | Position  |  Pixel data (1 byte per) ]\n```\n\nIf the position is positive (two's complement), this is the start of a line. If it's negative, take its absolute value and plot on the current line (the first line only have negative sections). Simply put the pixel data in the line buffer linearly at the specified position. Any part of a line that is not explicitly colored is transparent. Each pixel is encoded in a fixed palette, which can be found in extract.py\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjifish%2Felfish-extractor","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjifish%2Felfish-extractor","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjifish%2Felfish-extractor/lists"}