{"id":15102084,"url":"https://github.com/rcowsill/jpegsawmill","last_synced_at":"2026-02-17T15:35:40.737Z","repository":{"id":232986235,"uuid":"762473549","full_name":"rcowsill/JPEGSawmill","owner":"rcowsill","description":"A web application that shows the individual scans in progressive JPEGs","archived":false,"fork":false,"pushed_at":"2024-05-30T12:00:51.000Z","size":275,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-02-10T22:35:59.885Z","etag":null,"topics":["jpeg","preactjs","webassembly"],"latest_commit_sha":null,"homepage":"https://rcowsill.github.io/JPEGSawmill/","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"agpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rcowsill.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"COPYING","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":"2024-02-23T21:19:16.000Z","updated_at":"2024-05-30T11:59:30.000Z","dependencies_parsed_at":"2024-05-20T11:48:42.728Z","dependency_job_id":"0d38f08c-5645-48e4-a09e-92db60786abd","html_url":"https://github.com/rcowsill/JPEGSawmill","commit_stats":{"total_commits":109,"total_committers":1,"mean_commits":109.0,"dds":0.0,"last_synced_commit":"385fabb504a4271387d173a61b9bdf1585ddf6c7"},"previous_names":["rcowsill/jpegsawmill"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rcowsill%2FJPEGSawmill","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rcowsill%2FJPEGSawmill/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rcowsill%2FJPEGSawmill/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rcowsill%2FJPEGSawmill/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rcowsill","download_url":"https://codeload.github.com/rcowsill/JPEGSawmill/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247332521,"owners_count":20921852,"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":["jpeg","preactjs","webassembly"],"created_at":"2024-09-25T18:46:36.916Z","updated_at":"2025-10-10T20:33:04.831Z","avatar_url":"https://github.com/rcowsill.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# JPEG Sawmill\n\n## Overview\n\nJPEG Sawmill is a web application that splits up progressive JPEGs into their individual scans.\nThe image resulting from each scan can be viewed, as well as the differences between adjacent\nimages in the series. Progressive display can also be simulated in slow motion, as if the\nimage is being downloaded over a slow connection.\n\n\n## Background\n\nThe JPEG image standard supports both sequential and progressive encoding modes. Sequential\nJPEGs are encoded in a single \"scan\" from top left to bottom right. Progressive JPEGs\nreconstruct the image in a series of scans, where each subsequent scan improves image quality. \n\nProgressive mode is useful for websites, as the initial scans quickly provide an acceptable\nplaceholder while the rest is downloaded. Also, progressive JPEGs usually reduce file size\nbecause the rearranged image data is more compressible.\n\nJPEG progressive mode is highly customisable[^1]; the settings can be tuned for specific use\ncases or even optimised per-image.\n\n\n## Implementation Details\n\nImages are split into their constituent scans using the same general approach as \"[JPEG Scan Killer](#user-content-jsk)\".\nFirst, the markers at the end of each scan are located using the jpeg_inspector library. Then new\nimages are created, containing all the data before each marker with an \"End of Image\" marker\nappended.\n\nThe jpeg_inspector library was designed for use as a WebAssembly module. It avoids using file IO,\nso emscripten's virtual file system isn't needed. Instead the API just lets the calling JavaScript\nget the offset of the end of the next scan. This cuts the resulting .wasm size down to 8kB for a\nrelease build [^2].\n\nOn the JavaScript side, the new images for each scan are made using subarrays of the full JPEG\nbuffer. These are views onto the same underlying data. To display the images, `createObjectUrl`\nis used to allow them to be referenced from the DOM. This means the scan images don't need\nencoding as base64 data URLs.\n\nThis design means the memory required for processing is roughly twice the file size[^3][^4].\n\n\n## Thanks to:\n\n* Frederic Kayser for showing how to split a progressive JPEG into individual scans.\n  * \u003ca id=\"user-content-jsk\"\u003e\u003c/a\u003e[JSK -JPEG Scan Killer- progressive JPEG explained in slowmo](https://web.archive.org/web/20160830024109/http://encode.ru/threads/1800-JSK-JPEG-Scan-Killer-progressive-JPEG-explained-in-slowmo)\n  * [Source code (jsk.c)](https://gist.github.com/rcowsill/3fc903c92faaed7a9da745cde9f83799)\n\n* Karl Thibault for showing how to use Emscripten to embed JSK in a web app\n  * https://github.com/Notuom/progressive-jpeg-scans\n\n* The Emscripten authors for [Emscripten](https://emscripten.org)\n  * https://github.com/emscripten-core/emscripten\n\n* Sebastiano Merlino for liblittletest\n  * https://github.com/etr/liblittletest\n\n\n[^1]: Unfortunately JPEG encoders often hide this complexity behind a simple checkbox which activates progressive encoding with preset parameters.\n[^2]: Plus a 3kB JavaScript wrapper module from Emscripten\n[^3]: One copy of the file for JavaScript and another in WebAssembly linear memory\n[^4]: This is in addition to the memory the browser needs to decode and display each scan\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frcowsill%2Fjpegsawmill","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frcowsill%2Fjpegsawmill","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frcowsill%2Fjpegsawmill/lists"}