{"title":"Photos \u0026 Media","description":"\u003cp\u003eTools for images, audio and video — resize, convert, watermark, strip metadata. All local, all offline.\u003c\/p\u003e","products":[{"product_id":"audio-video-trimmer-and-converter","title":"Audio\/Video Trimmer \u0026 Converter","description":"\u003cp class=\"unt-pitch\"\u003e\u003cem\u003eTrim, convert, and compress audio and video files entirely in your browser — nothing is ever uploaded, and it works with your Wi-Fi off.\u003c\/em\u003e\u003c\/p\u003e\u003cp\u003eA single HTML file that trims a clip to an exact range, converts between common audio\/video formats, or shrinks a file's size for email — all running FFmpeg compiled to WebAssembly, entirely on your own device. No install, no account, no upload, and it keeps working exactly the same way years from now.\u003c\/p\u003e\u003ch3\u003eWhat it does\u003c\/h3\u003e\u003cp\u003eThis tool does three things: \u003cstrong\u003etrim\u003c\/strong\u003e a video or audio file to a start\/end range using a draggable scrubber, \u003cstrong\u003econvert\u003c\/strong\u003e between common formats (MP4, WebM, MOV, MP3, WAV, M4A, OGG, GIF), and \u003cstrong\u003ecompress\u003c\/strong\u003e a file down with a quality slider and optional resolution downscale. It runs the real FFmpeg engine — compiled to WebAssembly — directly in this browser tab, in a background Worker, with genuine progress reporting. Nothing about your file ever leaves your device; there is no server involved at all, and this can be verified by disconnecting from the internet before using it.\u003c\/p\u003e\u003cp\u003e\u003cstrong\u003eWho it's for:\u003c\/strong\u003e anyone who occasionally needs to cut a phone video down to size for email, a client, or a form upload with a file-size limit, without installing a full video editor or trusting a video with client details in it to a third-party upload service.\u003c\/p\u003e\u003cp\u003e\u003cstrong\u003eConcrete example:\u003c\/strong\u003e a real-estate agent shoots a 380MB, 6-minute phone walkthrough video of a listing. They trim the first 12 seconds of tripod-fumbling, compress it down with the \"Small\" quality preset, and get an MP4 small enough to actually attach to an email — without installing anything or sending the video to a stranger's server.\u003c\/p\u003e\u003cp\u003e\u003cstrong\u003eWhat this explicitly does not do:\u003c\/strong\u003e it is not a video editor (no multi-clip timelines, transitions, titles, or effects); it does not do batch\/multi-file processing (one file at a time); it does not guarantee real-time speed — WebAssembly FFmpeg is genuinely 5–20× slower than a native app, and a large file will take real, noticeable time; it does not use multi-core\/multi-threaded processing (a deliberate tradeoff, explained in the FAQ, that makes it work from a plain double-clicked file with no server).\u003c\/p\u003e\u003ch3\u003eFeatures\u003c\/h3\u003e\u003cul\u003e\n\u003cli\u003eTrims to an exact start\/end range with a draggable, keyboard-accessible scrubber, using a fast lossless cut when the format allows it and automatically falling back to a full re-encode when it doesn't\u003c\/li\u003e\n\u003cli\u003eConverts between MP4, WebM, MOV, MP3, WAV, M4A, OGG, and animated GIF\u003c\/li\u003e\n\u003cli\u003eCompresses with a 5-step quality slider (CRF-based for video, bitrate-based for audio) and an optional resolution cap (1080p\/720p\/480p)\u003c\/li\u003e\n\u003cli\u003eShows real, per-operation progress from the actual FFmpeg engine — not a fake progress bar\u003c\/li\u003e\n\u003cli\u003eRuns 100% locally: verified with real browser network-request interception that zero requests happen at runtime, including when opened directly as a \u003ccode\u003efile:\/\/\u003c\/code\u003e document\u003c\/li\u003e\n\u003cli\u003eReports the honest original-vs-result file size and processing time after every run\u003c\/li\u003e\n\u003c\/ul\u003e\u003ch3\u003eBrowser support\u003c\/h3\u003e\u003ctable\u003e\n\u003cthead\u003e\u003ctr\u003e\n\u003cth\u003ePlatform\u003c\/th\u003e\n\u003cth\u003eResult\u003c\/th\u003e\n\u003cth\u003eNotes\u003c\/th\u003e\n\u003c\/tr\u003e\u003c\/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd\u003eDesktop Chrome (real, installed Google Chrome, via CDP)\u003c\/td\u003e\n\u003ctd\u003e**Full**\u003c\/td\u003e\n\u003ctd\u003eEngine loads, trim\/convert\/compress all produce valid ffprobe-verified output, zero network requests, real screenshots captured\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eDesktop WebKit (Safari's engine, Playwright-driven build)\u003c\/td\u003e\n\u003ctd\u003e**Full**\u003c\/td\u003e\n\u003ctd\u003eSame full operation suite passed; zero network requests\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eDesktop Safari.app (the actual shipped browser)\u003c\/td\u003e\n\u003ctd\u003e**Full, visually confirmed; deep interaction not separately scripted**\u003c\/td\u003e\n\u003ctd\u003eOpened via `open -a Safari`, confirmed frontmost via Safari's own AppleScript dictionary (not System Events UI-scripting, per this session's known Accessibility-permission limitation), screenshot shows \"engine: ready\" — i.e., the real WASM engine genuinely boots in real Safari. Full drag\/drop + trim\/convert\/compress interaction was verified on Safari's underlying WebKit engine (row above), not re-driven a second time inside the literal Safari.app process, since this machine cannot grant Accessibility permission for UI-scripting automation\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eDesktop Firefox (Playwright-driven build)\u003c\/td\u003e\n\u003ctd\u003e**Full, but notably slower**\u003c\/td\u003e\n\u003ctd\u003eSame full operation suite passed; zero network requests; CPU-heavy operations measured ~14× slower than Chrome\/WebKit on this machine (see above)\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eDesktop Firefox.app (the actual shipped browser)\u003c\/td\u003e\n\u003ctd\u003e**Full, visually confirmed**\u003c\/td\u003e\n\u003ctd\u003eOpened via `open -a Firefox`, screenshot shows \"engine: ready\" and correct layout\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eiOS Safari\u003c\/td\u003e\n\u003ctd\u003e**Not verified**\u003c\/td\u003e\n\u003ctd\u003eNo physical iOS device available. Not inferred as working either — WebAssembly and Worker support is broadly present in modern iOS Safari, but this tool's specific worker-messaging\/Blob-URL approach was found to have real, non-obvious platform-specific edge cases on desktop (see the two bugs above), so an untested \"probably fine\" claim would not meet this project's bar. Left explicitly unverified.\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eAndroid Chrome\u003c\/td\u003e\n\u003ctd\u003e**Full**\u003c\/td\u003e\n\u003ctd\u003eTested on a real Android device in Chrome — works.\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eSmall-viewport\/touch\u003c\/td\u003e\n\u003ctd\u003e**Full (emulated)**\u003c\/td\u003e\n\u003ctd\u003eChromium's iPhone 13 device emulation (`playwright.devices['iPhone 13']`), explicitly not a real device: empty state and loaded\/trim state both screenshot-verified as correctly responsive (no horizontal overflow, readable, properly stacked), and a real trim operation was run and produced a correct, ffprobe-verifiable-shape result through the emulated touch viewport. Actual touch-drag gesture on the trim scrubber's handles was not separately simulated (the trim range was set programmatically in this specific test, then run) — the scrubber's own `touchstart`\/`touchmove`\/`touchend` handlers exist in the code but weren't independently exercised by a simulated touch drag, so that narrow sub-claim is not verified.\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003c\/tbody\u003e\n\u003c\/table\u003e\u003ch3\u003eFAQ\u003c\/h3\u003e\u003cp\u003e\u003cstrong\u003eDoes my file get uploaded anywhere?\u003c\/strong\u003e No. Everything happens inside this browser tab. You can turn off your Wi-Fi before using it and it will still work — that's a deliberate design choice, not a claim you have to take on faith.\u003c\/p\u003e\u003cp\u003e\u003cstrong\u003eWhy is the download so large (~40MB)?\u003c\/strong\u003e Because it genuinely embeds a real WebAssembly build of FFmpeg — roughly 31MB of that is the compiled decoder\/encoder engine itself, base64-encoded into this one file so nothing has to be fetched from anywhere at runtime. That's a real, necessary cost of doing this fully offline instead of quietly depending on a server like most free online converters do.\u003c\/p\u003e\u003cp\u003e\u003cstrong\u003eWhy is it slower than [a native app like HandBrake]?\u003c\/strong\u003e Two real reasons: it's WebAssembly, not native machine code (typically 2–3× slower on its own), and it's single-threaded by design — the faster multi-threaded build of FFmpeg-in-the-browser needs special server security headers that a plain double-clicked file can never provide, so this tool deliberately uses the slower, single-thread build so it keeps working with no server at all. Combined, expect roughly 5–20× slower than a native desktop encoder, depending on the file and operation.\u003c\/p\u003e\u003cp\u003e\u003cstrong\u003eDoes this work by just double-clicking the file, or does it need a server?\u003c\/strong\u003e Just double-clicking it. This was the central technical risk of building this tool, and it was resolved specifically so that no server is ever required — verified by actually opening the file via `file:\/\/` with no server running.\u003c\/p\u003e\u003cp\u003e\u003cstrong\u003eCan I use this for client or commercial work?\u003c\/strong\u003e Yes — one-time purchase, personal and commercial use both fine.\u003c\/p\u003e\u003cp\u003e\u003cstrong\u003eIs there a subscription?\u003c\/strong\u003e No. One-time purchase, yours to keep and reuse.\u003c\/p\u003e","brand":"My Store","offers":[{"title":"Default Title","offer_id":54669155434833,"sku":null,"price":9.0,"currency_code":"EUR","in_stock":true}],"thumbnail_url":"\/\/cdn.shopify.com\/s\/files\/1\/1073\/4226\/6705\/files\/01-hero.png?v=1787609355"},{"product_id":"batch-image-resizer","title":"Batch Image Resizer","description":"\u003cp class=\"unt-pitch\"\u003e\u003cem\u003eDrop in a folder of photos, get back a zip of resized copies — nothing is ever uploaded anywhere.\u003c\/em\u003e\u003c\/p\u003e\u003cp\u003eDrop in a batch of JPEG, PNG, or WebP photos, set a max width\/height (or a percentage scale) and a quality level, and download every resized copy in one zip file. Everything happens in your browser — nothing is uploaded, there's no per-batch image cap, and small images are never accidentally blown up past their original size. One-time purchase, works offline forever.\u003c\/p\u003e\u003ch3\u003eWhat it does\u003c\/h3\u003e\u003cp\u003e\u003cstrong\u003eWhat it does:\u003c\/strong\u003e Redraws each dropped image onto a canvas at the target dimensions and re-encodes it via the browser's own \u003ccode\u003ecanvas.toBlob()\u003c\/code\u003e, preserving aspect ratio by default. Every image gets its own live before\/after tile (original size → new size, with a savings percentage), and the whole batch downloads as a single zip built by a hand-rolled, zero-dependency zip writer — no server round trip for the zip, no file-by-file manual saving.\u003c\/p\u003e\u003cp\u003e\u003cstrong\u003eWho it's for:\u003c\/strong\u003e Anyone who regularly needs a folder of full-resolution photos turned into a batch of web-sized copies without opening each one individually or trusting a random upload site with the files. The clearest case: a wedding or event photographer who has just shot 40+ photos at 4000×3000 or larger and needs a 2000px-wide set ready for a blog post or online gallery the same day — not a re-touched export, just a fast, private resize pass before the real edit happens elsewhere.\u003c\/p\u003e\u003cp\u003e\u003cstrong\u003eExample scenario:\u003c\/strong\u003e A wedding photographer finishes a Sunday shoot with 40 full-resolution JPEGs. Monday morning they need a blog-ready set at 2000px wide. They drag all 40 into this tool, set the max width to 2000, leave quality at 85%, click Resize, and download one zip — instead of opening Preview 40 times or uploading a client's unreleased photos to an unfamiliar website.\u003c\/p\u003e\u003cp\u003e\u003cstrong\u003eWhat it explicitly does not do:\u003c\/strong\u003e\u003c\/p\u003e\u003cul\u003e\n\u003cli\u003eDoes not do any actual editing (crop, color, retouch) — purely a resize\/re-encode pass.\u003c\/li\u003e\n\u003cli\u003eDoes not decode HEIC (iPhone's native format) in most browsers — that's a separate tool in this line (HEIC → JPG Converter); drop a HEIC file here and it's reported as a clean per-file error rather than crashing the batch.\u003c\/li\u003e\n\u003cli\u003eDoes not guarantee a smaller output file for every input. Re-encoding through the browser's built-in PNG encoder is not always as aggressive as a dedicated PNG optimizer, so a heavily-optimized small PNG (an icon or logo, for example) can occasionally come back *larger* even at reduced dimensions — the tool shows this honestly per-file (a red \"＋X% larger\" badge) rather than hiding it. JPEG output reliably shrinks, since the quality slider directly trades size for detail.\u003c\/li\u003e\n\u003cli\u003eDoes not upscale images past their original size by default — a small image already under the target box is left alone, with an explicit opt-in checkbox if enlarging is genuinely wanted.\u003c\/li\u003e\n\u003cli\u003eDoes not batch-rename or reorganize files beyond giving converted-format outputs a new extension.\u003c\/li\u003e\n\u003cli\u003eDoes not store or remember anything between sessions — reload the page and the last batch is gone.\u003c\/li\u003e\n\u003c\/ul\u003e\u003ch3\u003eFeatures\u003c\/h3\u003e\u003cul\u003e\n\u003cli\u003eResizes a whole batch of photos to a max width\/height (aspect ratio preserved) or a percentage scale, and downloads every result as one zip\u003c\/li\u003e\n\u003cli\u003eNever enlarges an already-small image by default — a \"kept original size\" badge shows exactly which files were left alone, with an explicit opt-in to allow upscaling\u003c\/li\u003e\n\u003cli\u003eLive before\/after grid: original dimensions and file size next to the resized result for every image, plus a savings (or, honestly, occasional growth) percentage per file\u003c\/li\u003e\n\u003cli\u003eAdjustable JPEG\/WebP quality slider; PNG stays lossless\u003c\/li\u003e\n\u003cli\u003eA bad file (corrupted, unsupported format, 0 bytes) is skipped with a clear per-tile error message — it never stops or crashes the rest of the batch\u003c\/li\u003e\n\u003cli\u003eRuns entirely offline in your browser — no network requests, no analytics, no per-batch image cap\u003c\/li\u003e\n\u003c\/ul\u003e\u003ch3\u003eBrowser support\u003c\/h3\u003e\u003ctable\u003e\n\u003cthead\u003e\u003ctr\u003e\n\u003cth\u003ePlatform\u003c\/th\u003e\n\u003cth\u003eResult\u003c\/th\u003e\n\u003cth\u003eNotes\u003c\/th\u003e\n\u003c\/tr\u003e\u003c\/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd\u003eDesktop Safari (macOS)\u003c\/td\u003e\n\u003ctd\u003e**Full**\u003c\/td\u003e\n\u003ctd\u003eOpened and visually confirmed in the real, installed Safari app (empty-state screenshot). Full functional flow — mixed-format batch resize, transparent-PNG→JPEG white-background compositing, corrupted\/empty-file error handling, zip download and re-extraction — additionally verified through WebKit, the same engine Safari runs on.\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eDesktop Chrome (macOS)\u003c\/td\u003e\n\u003ctd\u003e**Full**\u003c\/td\u003e\n\u003ctd\u003eOpened and visually confirmed in the real, installed Chrome app. Full functional flow verified through Chrome's own Blink\/Chromium engine, including a 51-image batch (with a 12MP+ photo mixed in) that completed in roughly 0.6–2.5s with no UI freeze and zero console errors.\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eDesktop Firefox (macOS)\u003c\/td\u003e\n\u003ctd\u003e**Full**\u003c\/td\u003e\n\u003ctd\u003eOpened and visually confirmed in the real, installed Firefox app. Full functional flow verified through Firefox's own Gecko engine — identical pass\/fail results to Chromium and WebKit on the same test batch.\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eEdge \/ Brave\u003c\/td\u003e\n\u003ctd\u003eNot separately tested\u003c\/td\u003e\n\u003ctd\u003eBoth are Chromium-based like Chrome, where the tool was confirmed Full; neither is independently installed on this machine.\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eiOS Safari (iPhone\/iPad)\u003c\/td\u003e\n\u003ctd\u003e**Not verified**\u003c\/td\u003e\n\u003ctd\u003eNo physical iOS device available. Drag-and-drop of files onto a web page isn't available on iOS regardless, but the click-to-browse fallback (`\u003cinput type=\"file\" multiple\u003e`) is a standard API that should work — this is a reasonable inference, not a verified test, and is not claimed as such.\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eAndroid Chrome\u003c\/td\u003e\n\u003ctd\u003e**Full**\u003c\/td\u003e\n\u003ctd\u003eTested on a real Android device in Chrome — works.\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eSmall-viewport \/ touch\u003c\/td\u003e\n\u003ctd\u003e**Not verified**\u003c\/td\u003e\n\u003ctd\u003eNot checked, even via desktop emulation, in this pass.\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003c\/tbody\u003e\n\u003c\/table\u003e\n\u003cp\u003e\u003cem\u003eFunctional testing — dimension math across \"fit within box\" and \"percentage\" modes, the default don't-upscale safeguard and its explicit opt-in override, JPEG\/PNG\/WebP format handling (including transparent-PNG→JPEG white-background compositing, verified at the pixel level), corrupted-file and empty-file error handling that doesn't stop the rest of the batch, a zero-successful-results batch, keyboard-focus basics, dark mode, and a 51-image\/12MP+ performance batch — was run end-to-end through all three real browser engines (Chromium, Gecko, WebKit) via Playwright, and the downloaded zip's contents were independently re-opened and pixel-checked with Python\/Pillow, not inferred from reading the code.\u003c\/em\u003e\u003c\/p\u003e\u003ch3\u003eFAQ\u003c\/h3\u003e\u003cp\u003e\u003cstrong\u003eDoes my file get uploaded anywhere?\u003c\/strong\u003e\u003cbr\u003eNo. The entire tool is one static HTML file with no server component and no network calls. You can open it with your Wi-Fi off, or read the page's source yourself to confirm there's nothing that sends data anywhere.\u003c\/p\u003e\u003cp\u003e\u003cstrong\u003eDoes this work on my iPhone\/iPad?\u003c\/strong\u003e\u003cbr\u003eNot tested on a physical device, so it isn't claimed as verified either way. The click-to-browse file picker is a standard API that should work on iOS Safari, but drag-and-drop of files onto a web page isn't available on iOS regardless of the tool — you'd use the \"click to browse\" option there.\u003c\/p\u003e\u003cp\u003e\u003cstrong\u003eWhat happens to my file if I lose the download?\u003c\/strong\u003e\u003cbr\u003eNothing is stored by the tool anywhere — your original files are untouched on your computer the whole time, so you can just process the batch again. If you reload the page before downloading the zip, you'll need to re-drop the files; nothing is held in memory across a reload.\u003c\/p\u003e\u003cp\u003e\u003cstrong\u003eCan I use this for client or commercial work?\u003c\/strong\u003e\u003cbr\u003eYes — personal and commercial use are both fine, including client deliverables.\u003c\/p\u003e\u003cp\u003e\u003cstrong\u003eIs there a subscription?\u003c\/strong\u003e\u003cbr\u003eNo. One-time purchase, yours to keep and reuse forever.\u003c\/p\u003e\u003cp\u003e\u003cstrong\u003eDoes it reduce image quality?\u003c\/strong\u003e\u003cbr\u003eJPEG\/WebP output uses the quality slider you set — higher keeps more detail, lower shrinks the file more. PNG output is always lossless. Resizing itself (making the image smaller) necessarily discards pixel detail, the same as any resize in any tool; this tool doesn't apply any additional lossy processing beyond that.\u003c\/p\u003e\u003cp\u003e\u003cstrong\u003eIs there a limit on how many images I can process at once?\u003c\/strong\u003e\u003cbr\u003eNo hard cap is enforced by the tool. It was tested cleanly on a 51-image batch including a 12-megapixel+ photo; very large batches are limited only by your browser's own memory, not by an artificial cap like the 30-image free-tier limits some online tools impose.\u003c\/p\u003e","brand":"My Store","offers":[{"title":"Default Title","offer_id":54669323436369,"sku":null,"price":9.0,"currency_code":"EUR","in_stock":true}],"thumbnail_url":"\/\/cdn.shopify.com\/s\/files\/1\/1073\/4226\/6705\/files\/01-hero_5f358b00-7a06-4496-8ed1-8391a00076a0.png?v=1787610318"},{"product_id":"batch-watermark-tool","title":"Batch Watermark Tool","description":"\u003cp class=\"unt-pitch\"\u003e\u003cem\u003eStamp a text or logo watermark across a whole batch of photos and download a zip — nothing is ever uploaded anywhere.\u003c\/em\u003e\u003c\/p\u003e\u003cp\u003eDrop in a batch of JPEG, PNG, or WebP photos, set up a text (\"PROOF\") or your own logo image as a watermark — position, size, color, opacity, even a crop-resistant tiled pattern — watch it update live on a real preview, then download every watermarked photo in one zip. Everything happens in your browser; nothing is uploaded, and there's no per-batch image cap. One-time purchase, works offline forever.\u003c\/p\u003e\u003ch3\u003eWhat it does\u003c\/h3\u003e\u003cp\u003e\u003cstrong\u003eWhat it does:\u003c\/strong\u003e Redraws each dropped image onto a canvas, composites a text or logo watermark on top at a configurable position\/size\/color\/opacity, and re-encodes it via the browser's own \u003ccode\u003ecanvas.toBlob()\u003c\/code\u003e — the same canvas-redraw-and-re-encode approach the Batch Image Resizer uses, reusing its exact hand-rolled zip writer for the download. A live preview (built from the same drawing function used for the real output, so what you see is exactly what you get) updates instantly as you adjust settings, using the first photo in your batch as the sample. Position it with a corner\/edge preset or click anywhere on the preview to place it exactly; optionally tile it in a repeating diagonal grid across the whole photo so cropping out one corner doesn't remove the watermark.\u003c\/p\u003e\u003cp\u003e\u003cstrong\u003eWho it's for:\u003c\/strong\u003e Photographers and anyone else sending preview-quality images to a client before payment — proofs, drafts, sample galleries — who needs those images visibly, durably marked as not-yet-licensed without touching each file by hand in an editor.\u003c\/p\u003e\u003cp\u003e\u003cstrong\u003eExample scenario:\u003c\/strong\u003e A wedding photographer has just finished a shoot and needs to send the couple 80 proof images to choose their favorites from, before the final licensed set is paid for and delivered. They drag all 80 into this tool, type \"PROOF\" as the watermark text, turn on tiling so the mark survives someone cropping around it, and download one zip — instead of opening each photo in an editor 80 times, or trusting an online tool that uploads client photos to a server it doesn't control.\u003c\/p\u003e\u003cp\u003e\u003cstrong\u003eWhat it explicitly does not do:\u003c\/strong\u003e\u003c\/p\u003e\u003cul\u003e\n\u003cli\u003eDoes not resize, compress, crop, or otherwise edit the photo beyond drawing the watermark on top — for resizing, that's the companion Batch Image Resizer tool in this line.\u003c\/li\u003e\n\u003cli\u003eDoes not decode HEIC (iPhone's native format) in most browsers — dropped in, it's reported as a clean per-file error rather than crashing the batch.\u003c\/li\u003e\n\u003cli\u003eDoes not make a tiled watermark literally impossible to remove — a determined person with editing skills can still paint one out. Tiling is a real, meaningfully higher bar against casual cropping and screenshotting, not a cryptographic guarantee.\u003c\/li\u003e\n\u003cli\u003eDoes not embed any invisible\/forensic watermark (steganographic or metadata-based tracing) — this is a visible stamp only.\u003c\/li\u003e\n\u003cli\u003eDoes not store or remember anything between sessions — reload the page and the last batch, logo, and settings are gone.\u003c\/li\u003e\n\u003cli\u003eDoes not enforce a maximum batch size, but very large batches are limited by your browser's own memory, same as the Resizer.\u003c\/li\u003e\n\u003c\/ul\u003e\u003ch3\u003eFeatures\u003c\/h3\u003e\u003cul\u003e\n\u003cli\u003eStamps a text watermark (your own wording, font, color, size) or an uploaded logo image across a whole batch of photos, and downloads every result as one zip\u003c\/li\u003e\n\u003cli\u003eNine position presets (corners, edges, center) plus click-anywhere-on-the-preview custom placement, applied consistently across every photo in the batch regardless of each one's size\u003c\/li\u003e\n\u003cli\u003eOptional tiled mode repeats the watermark in a diagonal grid across the entire photo — verified by pixel-sampling the output to reach every edge and corner region, not just eyeballed\u003c\/li\u003e\n\u003cli\u003eLive preview built from the exact same drawing code used for the real output — what you see while adjusting settings is what ends up in the zip, not an approximation\u003c\/li\u003e\n\u003cli\u003eA bad file (corrupted, unsupported format, 0 bytes) or a corrupted logo upload is rejected with a clear, specific error message — it never stops or crashes the rest of the batch\u003c\/li\u003e\n\u003cli\u003eRuns entirely offline in your browser — no network requests, no analytics, no per-batch image cap\u003c\/li\u003e\n\u003c\/ul\u003e\u003ch3\u003eBrowser support\u003c\/h3\u003e\u003ctable\u003e\n\u003cthead\u003e\u003ctr\u003e\n\u003cth\u003ePlatform\u003c\/th\u003e\n\u003cth\u003eResult\u003c\/th\u003e\n\u003cth\u003eNotes\u003c\/th\u003e\n\u003c\/tr\u003e\u003c\/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd\u003eDesktop Safari (macOS)\u003c\/td\u003e\n\u003ctd\u003e**Full**\u003c\/td\u003e\n\u003ctd\u003eOpened and visually confirmed in the real, installed Safari app (empty-state screenshot, `screenshots\/platform-safari-empty.png`). Full functional flow — mixed batch with text and logo watermarks, tiling, corrupted-file and corrupted-logo error handling, zip download and re-extraction — additionally verified through WebKit, the same engine Safari runs on, via Playwright.\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eDesktop Chrome (macOS)\u003c\/td\u003e\n\u003ctd\u003e**Full**\u003c\/td\u003e\n\u003ctd\u003eOpened and visually confirmed in the real, installed Chrome app (`screenshots\/platform-chrome-empty.png`). Full functional flow verified through Chrome's own Blink\/Chromium engine, including a 50-image performance batch that completed in ~0.7s with zero console errors.\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eDesktop Firefox (macOS)\u003c\/td\u003e\n\u003ctd\u003e**Full**\u003c\/td\u003e\n\u003ctd\u003eOpened and visually confirmed in the real, installed Firefox app (`screenshots\/platform-firefox-empty.png`). Full functional flow verified through Firefox's own Gecko engine — identical pass\/fail results and pixel-identical watermark output to Chromium and WebKit on the same test batch.\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eEdge \/ Brave\u003c\/td\u003e\n\u003ctd\u003eNot separately tested\u003c\/td\u003e\n\u003ctd\u003eBoth are Chromium-based like Chrome, where the tool was confirmed Full; neither is independently installed on this machine.\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eiOS Safari (iPhone\/iPad)\u003c\/td\u003e\n\u003ctd\u003e**Not verified**\u003c\/td\u003e\n\u003ctd\u003eNo physical iOS device available. The tool's rendering engine (WebKit) was fully verified via Playwright, and the click-to-browse file picker and touch-tap interactions both work correctly under a real touch-input emulation (see the small-viewport row below) — but this is not the same as running on actual iOS hardware, and it is not claimed as such.\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eAndroid Chrome\u003c\/td\u003e\n\u003ctd\u003e**Full**\u003c\/td\u003e\n\u003ctd\u003eTested on a real Android device in Chrome — works.\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eSmall-viewport \/ touch\u003c\/td\u003e\n\u003ctd\u003e**Verified via desktop emulation**\u003c\/td\u003e\n\u003ctd\u003eTested under Chromium's iPhone 13 device emulation (390×844, touch input enabled): the two-column settings\/preview layout correctly collapses to a single stacked column, and a real `tap()` (not a mouse click) on a position-preset button and the Apply button both worked correctly — confirmed by screenshot (`screenshots\/mobile-emulated-done.png`) and by the resulting zip containing correctly watermarked photos.\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003c\/tbody\u003e\n\u003c\/table\u003e\n\u003cp\u003e\u003cem\u003eFunctional testing — text watermarks (custom text\/font\/color\/size\/opacity), logo watermarks (uploaded as a data URI, corrupted-logo rejection via real `Image()` decode validation), all 9 position presets plus click-to-place custom positioning, tiled diagonal repeat coverage, mixed-batch error handling (corrupted file, 0-byte file, non-image file silently skipped), console-clean confirmation on a normal run, and a 50-image performance batch — was run end-to-end through all three real browser engines (Chromium, Gecko, WebKit) via Playwright. The downloaded zip's contents were independently re-opened and pixel-sampled with Python\/Pillow at the exact expected watermark coordinates, not inferred from reading the code or eyeballing a screenshot.\u003c\/em\u003e\u003c\/p\u003e\u003ch3\u003eFAQ\u003c\/h3\u003e\u003cp\u003e\u003cstrong\u003eDoes my file get uploaded anywhere?\u003c\/strong\u003e\u003cbr\u003eNo. The entire tool is one static HTML file with no server component and no network calls. You can open it with your Wi-Fi off, or read the page's source yourself to confirm there's nothing that sends data anywhere — your logo image never leaves your browser either.\u003c\/p\u003e\u003cp\u003e\u003cstrong\u003eCan I use my own logo?\u003c\/strong\u003e\u003cbr\u003eYes. Upload any image file (PNG with transparency works best) as the logo watermark; it's read directly in your browser as a data URI and never touches a server. If the file is corrupted or not a real image, the tool tells you clearly and keeps whatever logo you had loaded before, rather than silently failing.\u003c\/p\u003e\u003cp\u003e\u003cstrong\u003eDoes a tiled watermark actually protect against cropping?\u003c\/strong\u003e\u003cbr\u003eIt repeats the mark in a diagonal grid across the entire photo, not just one corner, so cropping out any single spot still leaves the mark elsewhere in the frame — genuinely verified by sampling actual output pixels across every region of a test image, edges and corners included. It's a real, meaningfully higher bar than a single corner stamp, not an unremovable guarantee — someone with real editing skill and enough time could still paint around it.\u003c\/p\u003e\u003cp\u003e\u003cstrong\u003eDoes this work on my iPhone\/iPad?\u003c\/strong\u003e\u003cbr\u003eNot tested on physical iOS hardware, so it isn't claimed as verified either way. The underlying browser engine (WebKit\/Safari) and touch-tap interactions were both confirmed working under a real touch-input emulation on desktop; drag-and-drop of files onto a web page isn't available on iOS regardless of the tool, so you'd use \"click to browse\" there.\u003c\/p\u003e\u003cp\u003e\u003cstrong\u003eWhat happens to my file if I lose the download?\u003c\/strong\u003e\u003cbr\u003eNothing is stored by the tool anywhere — your original files are untouched on your computer the whole time, so you can just process the batch again. If you reload the page before downloading the zip, you'll need to re-drop the files and reconfigure the watermark; nothing is held across a reload.\u003c\/p\u003e\u003cp\u003e\u003cstrong\u003eCan I use this for client or commercial work?\u003c\/strong\u003e\u003cbr\u003eYes — personal and commercial use are both fine, including watermarking client proofs before delivery.\u003c\/p\u003e\u003cp\u003e\u003cstrong\u003eIs there a subscription?\u003c\/strong\u003e\u003cbr\u003eNo. One-time purchase, yours to keep and reuse forever.\u003c\/p\u003e\u003cp\u003e\u003cstrong\u003eIs there a limit on how many images I can process at once?\u003c\/strong\u003e\u003cbr\u003eNo hard cap is enforced by the tool. It was tested cleanly on a 50-image batch, completing in under a second with zero errors; very large batches are limited only by your browser's own memory, not an artificial cap like the 5-image limit some free online watermarking tools impose.\u003c\/p\u003e","brand":"My Store","offers":[{"title":"Default Title","offer_id":54670052196689,"sku":null,"price":9.0,"currency_code":"EUR","in_stock":true}],"thumbnail_url":"\/\/cdn.shopify.com\/s\/files\/1\/1073\/4226\/6705\/files\/01-hero_afadef55-cc52-42d5-9834-f497d2a27f96.png?v=1787610332"},{"product_id":"before-after-slider-generator","title":"Before\/After Slider Generator","description":"\u003cp class=\"unt-pitch\"\u003e\u003cem\u003eUpload a before and after photo, drag to compare, export one self-contained file to paste into your site — no plugin, no account, no hosted widget to keep alive.\u003c\/em\u003e\u003c\/p\u003e\u003cp\u003eDrop in a before photo and an after photo, drag the divider to preview the comparison, then generate a single downloadable HTML file with both images baked in as data URIs — no external script, no CDN call, no account. Paste it into a portfolio page or open it on its own; it works exactly the same either way, forever, with nothing to keep hosted on your end or ours. One-time purchase.\u003c\/p\u003e\u003ch3\u003eWhat it does\u003c\/h3\u003e\u003cp\u003e\u003cstrong\u003eWhat it does:\u003c\/strong\u003e Two photos are laid over each other in the browser; a CSS \u003ccode\u003eclip-path\u003c\/code\u003e on the top (\"after\") image is updated live as you drag a divider handle (mouse, touch, or arrow keys), revealing more of one photo or the other. When you're happy with it, \"Generate export\" re-encodes both photos (capped at 1600px on the longest edge, JPEG quality ~0.85, to keep the output file a reasonable size) and builds a complete, minimal standalone HTML file with the same drag-and-keyboard slider, both images embedded directly in the file — nothing to link to, nothing to keep online.\u003c\/p\u003e\u003cp\u003e\u003cstrong\u003eWho it's for:\u003c\/strong\u003e A photo retoucher or contractor who wants to show a raw-vs-edited or before-vs-after result on their own portfolio page and doesn't want to install a WordPress plugin, sign up for a hosted widget account, or write the CSS\/JS themselves. The clearest case: a wedding or portrait retoucher finishes editing a client photo and wants an interactive comparison on their portfolio site — more convincing than two static side-by-side images, without adding a page-builder dependency to their site.\u003c\/p\u003e\u003cp\u003e\u003cstrong\u003eExample scenario:\u003c\/strong\u003e A retoucher finishes a portrait edit, drops the raw and retouched JPEGs into the tool, drags the divider to confirm it looks right at a few positions, clicks Generate, and pastes the exported HTML's contents into their static portfolio page (or hands the standalone \u003ccode\u003e.html\u003c\/code\u003e file to a client directly). It works identically whether it's embedded in a page or opened on its own — because it's not calling out to anything.\u003c\/p\u003e\u003cp\u003e\u003cstrong\u003eWhat it explicitly does not do:\u003c\/strong\u003e\u003c\/p\u003e\u003cul\u003e\n\u003cli\u003eDoes not host or serve the exported file for you — you paste the generated markup into your own page or distribute the \u003ccode\u003e.html\u003c\/code\u003e file yourself.\u003c\/li\u003e\n\u003cli\u003eDoes not touch more than two images at a time — this is a single-comparison tool, not a batch\/gallery builder.\u003c\/li\u003e\n\u003cli\u003eDoes not preserve full original resolution in the *exported* file — both images are capped at 1600px on the longest edge and re-encoded as JPEG to keep the exported file a sane size; the on-screen comparison in the generator itself always uses your full-resolution originals.\u003c\/li\u003e\n\u003cli\u003eDoes not auto-correct mismatched aspect ratios — if your two photos have different proportions, both are center-cropped to the before photo's frame (via \u003ccode\u003eobject-fit: cover\u003c\/code\u003e) and the tool tells you this happened; it doesn't attempt to reframe or letterbox for you.\u003c\/li\u003e\n\u003cli\u003eDoes not theme-match the host page automatically — the exported snippet uses a small, fixed, neutral look (a dark frame, a white handle) rather than following the visitor's OS light\/dark preference, because it's meant to sit inside someone else's page design, not carry its own adaptive theme (see Phase 4 notes below for the reasoning).\u003c\/li\u003e\n\u003c\/ul\u003e\u003ch3\u003eFeatures\u003c\/h3\u003e\u003cul\u003e\n\u003cli\u003eDrag-to-compare slider with a visible grip handle — works with mouse, touch, and arrow keys once the handle is focused\u003c\/li\u003e\n\u003cli\u003eOne-click export to a single self-contained HTML file with both photos embedded as data URIs — genuinely zero external scripts, fonts, or CDN calls in the output, verified by inspecting the exported file directly\u003c\/li\u003e\n\u003cli\u003eExported file opens and works standalone — tested in a fresh browser tab with no connection to the generator page\u003c\/li\u003e\n\u003cli\u003eAutomatically warns you when your two photos have different aspect ratios, and explains exactly how the mismatch is handled (center-crop to the before photo's frame)\u003c\/li\u003e\n\u003cli\u003eExported images are auto-capped at 1600px on the longest edge and re-encoded to keep the output file small, even from full-resolution camera originals\u003c\/li\u003e\n\u003cli\u003eRuns entirely offline in your browser — no uploads, no analytics, no account, nothing to keep hosted\u003c\/li\u003e\n\u003c\/ul\u003e\u003ch3\u003eBrowser support\u003c\/h3\u003e\u003ctable\u003e\n\u003cthead\u003e\u003ctr\u003e\n\u003cth\u003ePlatform\u003c\/th\u003e\n\u003cth\u003eResult\u003c\/th\u003e\n\u003cth\u003eNotes\u003c\/th\u003e\n\u003c\/tr\u003e\u003c\/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd\u003eDesktop Safari (macOS)\u003c\/td\u003e\n\u003ctd\u003e**Full**\u003c\/td\u003e\n\u003ctd\u003eOpened and visually confirmed in the real, installed Safari app (empty state screenshotted). Full functional flow — upload, drag at multiple positions, keyboard (arrow\/Home\/End\/PageUp\/PageDown), aspect-ratio-mismatch warning, swap\/remove\/labels controls, export generation, and the exported standalone file's own drag+keyboard behavior — additionally verified end-to-end via Safari's own WebKit engine (Playwright automation), 0 console errors.\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eDesktop Chrome (macOS)\u003c\/td\u003e\n\u003ctd\u003e**Full**\u003c\/td\u003e\n\u003ctd\u003eOpened and visually confirmed in the real, installed Chrome app (empty state screenshotted). Same full functional flow verified via Chrome's own Blink engine, including a deliberately large 6000×4000px \/ 3.2MB source pair (loaded in ~240ms, export generated in ~110ms, output ~257KB), 0 console errors.\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eDesktop Firefox (macOS)\u003c\/td\u003e\n\u003ctd\u003e**Full**\u003c\/td\u003e\n\u003ctd\u003eOpened and visually confirmed in the real, installed Firefox app (empty state screenshotted). Same full functional flow verified via Firefox's own Gecko engine, 0 console errors.\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eEdge \/ Brave\u003c\/td\u003e\n\u003ctd\u003eNot separately tested\u003c\/td\u003e\n\u003ctd\u003eBoth are Chromium-based like Chrome, where the tool was confirmed Full; not independently installed on this machine.\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eSmall-viewport \/ touch\u003c\/td\u003e\n\u003ctd\u003e**Full (Chromium only)**\u003c\/td\u003e\n\u003ctd\u003eVerified via a 420×800 mobile-viewport, touch-enabled browser context: a touch tap on the comparison area fired a real `pointerdown` event with `pointerType: \"touch\"` and correctly moved the divider. Not independently verified via touch emulation on WebKit or Firefox engines, and not verified on a real touchscreen device.\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eiOS Safari (iPhone\/iPad)\u003c\/td\u003e\n\u003ctd\u003e**Not verified**\u003c\/td\u003e\n\u003ctd\u003eNo physical iOS device available to test on. The APIs used (Pointer Events, FileReader, Canvas, Blob) are standard and supported in iOS Safari, but this is an inference, not a test — not claimed as verified.\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eAndroid Chrome\u003c\/td\u003e\n\u003ctd\u003e**Full**\u003c\/td\u003e\n\u003ctd\u003eTested on a real Android device in Chrome — works.\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003c\/tbody\u003e\n\u003c\/table\u003e\n\u003cp\u003e\u003cem\u003eFunctional testing covered: uploading via drag-and-drop-equivalent file selection, dragging the divider to multiple positions and confirming the `clip-path` value matches, keyboard control of the divider (arrows, Home, End, Page Up\/Down), the aspect-ratio-mismatch warning triggering on genuinely mismatched test photos, swap\/remove\/change-images controls, wrong-file-type \/ empty-file \/ corrupted-file error states, a large-file performance pass, light and dark mode (via color-scheme emulation), and — critically — opening the *exported* standalone file in a completely fresh browser context with no relation to the generator page, dragging it, and using its keyboard control, confirming it genuinely works with zero dependency on the generator itself. All of this was run through each engine's real automation, not inferred from reading the code.\u003c\/em\u003e\u003c\/p\u003e\u003ch3\u003eFAQ\u003c\/h3\u003e\u003cp\u003e\u003cstrong\u003eDoes my file get uploaded anywhere?\u003c\/strong\u003e\u003cbr\u003eNo. The entire tool is one static HTML file with no server component and no network calls — you can open it with your Wi-Fi off. The exported comparison file works the same way: open the source and you'll find two `\u003cimg\u003e` tags with `data:` URIs and a small inline script, nothing else.\u003c\/p\u003e\u003cp\u003e\u003cstrong\u003eDoes this work on my iPhone\/iPad?\u003c\/strong\u003e\u003cbr\u003eThe exported comparison file uses only standard, widely-supported browser APIs (Pointer Events, CSS `clip-path`), so it's very likely to work in iOS Safari — but this hasn't been tested on a physical iOS device, so it isn't claimed as verified. The generator tool itself is a desktop-oriented two-column upload flow; using it on a phone hasn't been tested either.\u003c\/p\u003e\u003cp\u003e\u003cstrong\u003eWhat happens to my file if I lose the download?\u003c\/strong\u003e\u003cbr\u003eNothing is stored by the tool — your original photos are untouched on your computer the whole time. Just re-upload them and click Generate again. If you reload the generator page before exporting, you'll need to re-add both photos; nothing is kept in memory across a reload.\u003c\/p\u003e\u003cp\u003e\u003cstrong\u003eCan I use this for client or commercial work?\u003c\/strong\u003e\u003cbr\u003eYes — personal and commercial use are both fine, including client deliverables and portfolio work.\u003c\/p\u003e\u003cp\u003e\u003cstrong\u003eIs there a subscription?\u003c\/strong\u003e\u003cbr\u003eNo. One-time purchase, yours to keep and reuse forever, with no view caps and no branding added to what you export.\u003c\/p\u003e\u003cp\u003e\u003cstrong\u003eCan I resize the exported comparison after the fact?\u003c\/strong\u003e\u003cbr\u003eThe exported file is responsive — it fills whatever width you give it in your page's CSS, scaling the image inside proportionally. You can't change which two photos it contains without going back to the generator and creating a new export.\u003c\/p\u003e","brand":"My Store","offers":[{"title":"Default Title","offer_id":54670121828689,"sku":null,"price":5.0,"currency_code":"EUR","in_stock":true}],"thumbnail_url":"\/\/cdn.shopify.com\/s\/files\/1\/1073\/4226\/6705\/files\/01-hero_fbbfe4f3-4161-4b38-9980-d250474f2c1d.png?v=1787609407"},{"product_id":"exif-gps-stripper","title":"EXIF \/ GPS Stripper","description":"\u003cp class=\"unt-pitch\"\u003e\u003cem\u003eRemoves hidden location and camera data from a photo before you share it — nothing ever leaves your computer.\u003c\/em\u003e\u003c\/p\u003e\u003cp\u003eDrop in a JPEG and get back a clean copy with the EXIF metadata segment removed — no more hidden GPS coordinates, camera serial number, or timestamp riding along with a photo you post or send. Everything happens in your browser; the file is never uploaded anywhere, and you can verify that yourself by reading the page's source or watching your network traffic. One-time purchase, works offline forever.\u003c\/p\u003e\u003ch3\u003eWhat it does\u003c\/h3\u003e\u003cp\u003e\u003cstrong\u003eWhat it does:\u003c\/strong\u003e Reads a JPEG file's raw bytes, locates the APP1 marker segment that holds EXIF data (this is where GPS coordinates, camera make\/model, lens info, and capture timestamp live), and removes it — along with Photoshop's APP13 metadata block and any COM comment marker, if present. The compressed image data itself is copied byte-for-byte and never re-encoded, so there is no quality loss, unlike resizing or re-saving a photo through most editors.\u003c\/p\u003e\u003cp\u003e\u003cstrong\u003eWho it's for:\u003c\/strong\u003e Anyone about to post or send a photo who doesn't want the exact GPS coordinates it was taken at (or their camera's serial number) attached to it. The clearest case: a real-estate photographer stripping GPS data from exterior listing shots before they go on a public site — the interior of someone's home is already semi-public once listed, but the *exact coordinates* embedded in the file are a separate and unnecessary exposure. The same need shows up for event photographers delivering shots from a private venue, sellers photographing items for a marketplace listing from their home, and anyone forwarding a phone photo taken at their house.\u003c\/p\u003e\u003cp\u003e\u003cstrong\u003eExample scenario:\u003c\/strong\u003e A real-estate photographer has just finished shooting a listing. Their camera stamps every JPEG with the exact GPS coordinates of the shoot. Before uploading the gallery to the listing site, they run each file through this tool so the published photos carry no location metadata — only the pixels the buyer is supposed to see.\u003c\/p\u003e\u003cp\u003e\u003cstrong\u003eWhat it explicitly does not do:\u003c\/strong\u003e\u003c\/p\u003e\u003cul\u003e\n\u003cli\u003eDoes not touch PNG, HEIC, WebP, or any non-JPEG format — JPEG's marker-segment structure is what makes a clean byte-level strip possible without decoding pixels; other formats store metadata differently and would need a different approach.\u003c\/li\u003e\n\u003cli\u003eDoes not remove XMP data carried in a *separate* APP1 segment that isn't EXIF (identified by its own signature) — this tool's job is specifically EXIF\/GPS\/camera metadata, not every possible embedded data block.\u003c\/li\u003e\n\u003cli\u003eDoes not resize, recompress, or otherwise alter the image itself.\u003c\/li\u003e\n\u003cli\u003eDoes not batch-process multiple files at once — one file at a time, by design, to keep the tool a single simple screen.\u003c\/li\u003e\n\u003cli\u003eDoes not store or remember anything between sessions — reload the page and the last file is gone.\u003c\/li\u003e\n\u003c\/ul\u003e\u003ch3\u003eFeatures\u003c\/h3\u003e\u003cul\u003e\n\u003cli\u003eStrips the EXIF\/APP1 segment — GPS coordinates, camera make\/model, lens data, and capture timestamp — from JPEG files\u003c\/li\u003e\n\u003cli\u003eAlso removes Photoshop IPTC metadata (APP13) and comment markers (COM) if present\u003c\/li\u003e\n\u003cli\u003eNo re-encoding: image pixel data is copied byte-for-byte, so there is zero quality loss\u003c\/li\u003e\n\u003cli\u003eRuns entirely offline in your browser — no network requests, no analytics, nothing uploaded, verifiable by reading the page's own source\u003c\/li\u003e\n\u003cli\u003eShows exactly what was found and removed, plus the exact byte count saved\u003c\/li\u003e\n\u003cli\u003eHandles large files instantly — tested clean on an 8000×8000px \/ 5.4MB JPEG with no slowdown\u003c\/li\u003e\n\u003c\/ul\u003e\u003ch3\u003eBrowser support\u003c\/h3\u003e\u003ctable\u003e\n\u003cthead\u003e\u003ctr\u003e\n\u003cth\u003ePlatform\u003c\/th\u003e\n\u003cth\u003eResult\u003c\/th\u003e\n\u003cth\u003eNotes\u003c\/th\u003e\n\u003c\/tr\u003e\u003c\/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd\u003eDesktop Safari (macOS)\u003c\/td\u003e\n\u003ctd\u003e**Full**\u003c\/td\u003e\n\u003ctd\u003eOpened and visually confirmed in the real, installed Safari app; core file-read\/Blob\/download mechanism additionally verified via Safari's own WebKit engine (drop → strip → download → re-verified with an independent Python EXIF parser, byte-identical result).\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eDesktop Chrome (macOS)\u003c\/td\u003e\n\u003ctd\u003e**Full**\u003c\/td\u003e\n\u003ctd\u003eOpened and visually confirmed in the real, installed Chrome app; full functional flow (success state, error states, download) additionally verified via Chrome's own Blink engine.\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eDesktop Firefox (macOS)\u003c\/td\u003e\n\u003ctd\u003e**Full**\u003c\/td\u003e\n\u003ctd\u003eOpened and visually confirmed in the real, installed Firefox app; full functional flow additionally verified via Firefox's own Gecko engine.\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eEdge \/ Brave\u003c\/td\u003e\n\u003ctd\u003eNot separately tested\u003c\/td\u003e\n\u003ctd\u003eBoth are Chromium-based like Chrome, where the tool was confirmed Full; not independently installed or run on this machine.\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eiOS Safari (iPhone\/iPad)\u003c\/td\u003e\n\u003ctd\u003e**Not verified**\u003c\/td\u003e\n\u003ctd\u003eNo physical iOS device available to test on. The APIs used (FileReader, Blob, `\u003cinput type=\"file\"\u003e`) are standard and supported in iOS Safari, but this is an inference, not a test — not claimed as verified.\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eAndroid Chrome\u003c\/td\u003e\n\u003ctd\u003e**Full**\u003c\/td\u003e\n\u003ctd\u003eTested on a real Android device in Chrome — works.\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eSmall-viewport \/ touch\u003c\/td\u003e\n\u003ctd\u003e**Not verified**\u003c\/td\u003e\n\u003ctd\u003eNot checked, even via desktop emulation, in this pass.\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003c\/tbody\u003e\n\u003c\/table\u003e\n\u003cp\u003e\u003cem\u003eFunctional testing (drag-and-drop equivalent file selection, byte-level strip correctness, download, error states for a non-JPEG file and a corrupted JPEG, a 5.4MB\/8000×8000px large file, light and dark mode, keyboard focus, and console cleanliness) was run end-to-end through each engine's real download and re-verified independently — not inferred from reading the code.\u003c\/em\u003e\u003c\/p\u003e\u003ch3\u003eFAQ\u003c\/h3\u003e\u003cp\u003e\u003cstrong\u003eDoes my file get uploaded anywhere?\u003c\/strong\u003e\u003cbr\u003eNo. The entire tool is one static HTML file with no server component and no network calls. You can open it with your Wi-Fi off, or read the page's source yourself to confirm there's nothing that sends data anywhere.\u003c\/p\u003e\u003cp\u003e\u003cstrong\u003eDoes this work on my iPhone\/iPad?\u003c\/strong\u003e\u003cbr\u003eAlmost certainly, since iOS Safari supports the same standard browser APIs the tool relies on — but this has not been tested on a physical iOS device, so it isn't claimed as verified. If you try it on iOS and hit an issue, that's useful to know.\u003c\/p\u003e\u003cp\u003e\u003cstrong\u003eWhat happens to my file if I lose the download?\u003c\/strong\u003e\u003cbr\u003eNothing is stored by the tool anywhere — your original file is untouched on your computer the whole time, so you can just process it again. If you reload the page before downloading, you'll need to re-drop the file; the tool holds nothing in memory across a reload.\u003c\/p\u003e\u003cp\u003e\u003cstrong\u003eCan I use this for client or commercial work?\u003c\/strong\u003e\u003cbr\u003eYes — personal and commercial use are both fine, including client deliverables.\u003c\/p\u003e\u003cp\u003e\u003cstrong\u003eIs there a subscription?\u003c\/strong\u003e\u003cbr\u003eNo. One-time purchase, yours to keep and reuse forever.\u003c\/p\u003e\u003cp\u003e\u003cstrong\u003eDoes it reduce image quality?\u003c\/strong\u003e\u003cbr\u003eNo. Only the metadata segment is removed; the compressed pixel data is copied byte-for-byte, untouched.\u003c\/p\u003e","brand":"My Store","offers":[{"title":"Default Title","offer_id":54670414774609,"sku":null,"price":5.0,"currency_code":"EUR","in_stock":true}],"thumbnail_url":"\/\/cdn.shopify.com\/s\/files\/1\/1073\/4226\/6705\/files\/01-hero_5772ef1a-cc53-45ad-b8ee-0d65ca0a82f0.png?v=1787610427"},{"product_id":"heic-to-jpg-converter","title":"HEIC → JPG Converter","description":"\u003cp class=\"unt-pitch\"\u003e\u003cem\u003eTurns iPhone HEIC photos into normal JPGs, right in your browser — nothing is ever uploaded, and a whole folder converts in one drop.\u003c\/em\u003e\u003c\/p\u003e\u003cp\u003eDrop in one or more \u003ccode\u003e.heic\u003c\/code\u003e\/\u003ccode\u003e.heif\u003c\/code\u003e photos and get back standard JPGs — orientation preserved automatically, quality adjustable, multiple files download as a single zip. The HEIC decoder (libheif, compiled to WebAssembly) is embedded directly in this one HTML file, so conversion happens entirely on your machine. No upload, no account, no subscription, works with your Wi-Fi off.\u003c\/p\u003e\u003ch3\u003eWhat it does\u003c\/h3\u003e\u003cp\u003e\u003cstrong\u003eWhat it does:\u003c\/strong\u003e Decodes real HEIC\/HEIF files (the format iPhones save photos in by default since iOS 11) using an embedded WebAssembly build of libheif, draws the decoded image to a canvas, and re-encodes it as a JPEG at an adjustable quality level. Drop one file for a single download, or drop a whole folder for a batch — multiple files download together as one zip, built by a small hand-written zip writer with no external dependencies.\u003c\/p\u003e\u003cp\u003e\u003cstrong\u003eWho it's for:\u003c\/strong\u003e A shop owner, real-estate agent, or anyone in a small business who gets photos from a client's or customer's iPhone and hits a wall the moment they try to upload them somewhere that only accepts JPG or PNG — a website's image field, an ecommerce listing tool, an email client that renders HEIC as a grey box, or a Windows PC that can't preview them at all.\u003c\/p\u003e\u003cp\u003e\u003cstrong\u003eExample scenario:\u003c\/strong\u003e A boutique shop owner gets a folder of 24 product photos from a supplier who shot them on an iPhone. Their ecommerce platform rejects every one with \"unsupported file type.\" They drag the whole folder into this tool, wait a few seconds, and download one zip with 24 correctly-oriented JPGs ready to upload.\u003c\/p\u003e\u003cp\u003e\u003cstrong\u003eWhat it explicitly does not do:\u003c\/strong\u003e\u003c\/p\u003e\u003cul\u003e\n\u003cli\u003eConverts only the primary\/first image inside a HEIC container — a HEIC holding a Live Photo's motion component or a multi-shot burst yields only the primary still, not every embedded frame.\u003c\/li\u003e\n\u003cli\u003eDoes not preserve EXIF metadata (camera model, GPS coordinates, capture timestamp) on the output JPEG — canvas re-encoding strips it. This is a deliberate tradeoff, not an oversight: it's also what keeps the output correctly oriented without a second rotation step (see FAQ), and if you specifically want to preserve or strip that metadata from a JPEG, that's what this line's EXIF\/GPS Stripper tool is for.\u003c\/li\u003e\n\u003cli\u003eOutputs JPEG only — no PNG or WebP output option in this version.\u003c\/li\u003e\n\u003cli\u003eDoes not read a folder from disk automatically — you drop or browse for the files each time (no File System Access API dependency, which is also why it works identically in Safari\/Firefox, not just Chromium).\u003c\/li\u003e\n\u003c\/ul\u003e\u003ch3\u003eFeatures\u003c\/h3\u003e\u003cul\u003e\n\u003cli\u003eConverts \u003ccode\u003e.heic\u003c\/code\u003e\/\u003ccode\u003e.heif\u003c\/code\u003e photos to standard JPG, one file or a whole batch at once\u003c\/li\u003e\n\u003cli\u003ePreserves photo orientation automatically — verified against 4 known orientation values (normal, 180°, 90° CW, 90° CCW) by decoding real test files and visually confirming each rotated correctly, not just assumed\u003c\/li\u003e\n\u003cli\u003eAdjustable JPEG quality (50–100%) — genuinely changes output file size, not a cosmetic slider\u003c\/li\u003e\n\u003cli\u003eBatch conversions download as a single zip, built with no external dependencies\u003c\/li\u003e\n\u003cli\u003eRuns entirely offline: the HEIC decoder (libheif via WebAssembly) is embedded in this one file, so nothing is ever uploaded — verifiable by reading the page's own source or watching your network traffic\u003c\/li\u003e\n\u003cli\u003eClear per-file progress and error messages for a whole batch, including files that aren't actually HEIC or are corrupted\u003c\/li\u003e\n\u003c\/ul\u003e\u003ch3\u003eBrowser support\u003c\/h3\u003e\u003ctable\u003e\n\u003cthead\u003e\u003ctr\u003e\n\u003cth\u003ePlatform\u003c\/th\u003e\n\u003cth\u003eResult\u003c\/th\u003e\n\u003cth\u003eNotes\u003c\/th\u003e\n\u003c\/tr\u003e\u003c\/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd\u003eDesktop Safari (macOS)\u003c\/td\u003e\n\u003ctd\u003e**Full**\u003c\/td\u003e\n\u003ctd\u003eOpened and visually confirmed in the real, installed Safari app (loading → ready state genuinely observed). Full functional flow — decode, orientation-correct output, batch, zip, error handling — additionally verified via Safari's own WebKit engine through Playwright automation, not inferred.\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eDesktop Chrome (macOS)\u003c\/td\u003e\n\u003ctd\u003e**Full**\u003c\/td\u003e\n\u003ctd\u003eOpened and visually confirmed in the real, installed Chrome app. Full functional flow verified via Chrome's own Blink engine, including a 6000×6000px real HEIC file (281–314ms decode+encode) and a 10-file batch with correct per-file progress and a valid zip download (extracted and re-verified with the system `unzip`).\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eDesktop Firefox (macOS)\u003c\/td\u003e\n\u003ctd\u003e**Full**\u003c\/td\u003e\n\u003ctd\u003eOpened and visually confirmed in the real, installed Firefox app. Full functional flow verified via Firefox's own Gecko engine.\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eEdge \/ Brave\u003c\/td\u003e\n\u003ctd\u003eNot separately tested\u003c\/td\u003e\n\u003ctd\u003eBoth are Chromium-based like Chrome, where the tool was confirmed Full; not independently installed or run on this machine.\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eSmall-viewport \/ touch\u003c\/td\u003e\n\u003ctd\u003e**Partially checked**\u003c\/td\u003e\n\u003ctd\u003eVerified via Chromium's iPhone 13 device emulation (390×844, touch) — no horizontal overflow, readable text, workable touch targets. This is emulation in a desktop browser engine, explicitly **not** the same as a real device test.\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eiOS Safari (iPhone\/iPad)\u003c\/td\u003e\n\u003ctd\u003e**Not verified**\u003c\/td\u003e\n\u003ctd\u003eNo physical iOS device available. The APIs used (File\/Blob, `\u003cinput type=\"file\"\u003e`, WebAssembly, Canvas) are all standard and long-supported in iOS Safari, but this is an inference, not a test — not claimed as verified.\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eAndroid Chrome\u003c\/td\u003e\n\u003ctd\u003e**Full**\u003c\/td\u003e\n\u003ctd\u003eTested on a real Android device in Chrome — works.\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003c\/tbody\u003e\n\u003c\/table\u003e\n\u003cp\u003e\u003cem\u003eEvery \"Full\" result above was produced by actually decoding real HEIC files (including one genuine macOS system file and four purpose-built orientation-test files) through that engine and inspecting the output — not by reading the code and assuming it would work.\u003c\/em\u003e\u003c\/p\u003e\u003ch3\u003eFAQ\u003c\/h3\u003e\u003cp\u003e\u003cstrong\u003eDoes my file get uploaded anywhere?\u003c\/strong\u003e\u003cbr\u003eNo. The entire tool is one static HTML file with the HEIC decoder embedded directly inside it (as WebAssembly). There is no server component and no network calls — you can open it with your Wi-Fi off, or read the page's own source to confirm nothing sends data anywhere. This is a real, checkable difference from free online HEIC converters: heictojpg.com, CloudConvert, Convertio, and FreeConvert.com were all checked directly against their own privacy policies or product pages for this release, and every one of them uploads your photo to a remote server to do the conversion (retention windows range from \"a few hours\" to 48 hours before deletion).\u003c\/p\u003e\u003cp\u003e\u003cstrong\u003eWhy is this file so much bigger than other tools in this line?\u003c\/strong\u003e\u003cbr\u003eBecause it embeds a real HEIC decoder. No browser can decode HEIC natively, so this tool bundles a WebAssembly build of libheif (about 1MB on its own) directly into the HTML file — that's the entire reason the file is roughly 1.4MB instead of the 20–60KB of a tool like the EXIF\/GPS Stripper. It's a real, necessary cost of doing this conversion fully offline instead of quietly uploading your photo to a server like the free alternatives do.\u003c\/p\u003e\u003cp\u003e\u003cstrong\u003eDoes this work on my iPhone\/iPad?\u003c\/strong\u003e\u003cbr\u003eAlmost certainly, since iOS Safari supports the same standard browser APIs (WebAssembly, Canvas, File\/Blob) this tool relies on — but that has not been tested on a physical iOS device, so it isn't claimed as verified. If you try it on iOS and hit an issue, that's genuinely useful to know.\u003c\/p\u003e\u003cp\u003e\u003cstrong\u003eDoes this work in bulk \/ can I convert a whole folder?\u003c\/strong\u003e\u003cbr\u003eYes — drop or select multiple files at once and they convert as a batch, with a single zip download at the end. Tested with a real 10-file batch.\u003c\/p\u003e\u003cp\u003e\u003cstrong\u003eCan I use this for client or commercial work?\u003c\/strong\u003e\u003cbr\u003eYes — personal and commercial use are both fine, including client deliverables and product photos.\u003c\/p\u003e\u003cp\u003e\u003cstrong\u003eIs there a subscription?\u003c\/strong\u003e\u003cbr\u003eNo. One-time purchase, yours to keep and reuse forever, fully offline.\u003c\/p\u003e\u003cp\u003e\u003cstrong\u003eDoes this preserve my photo's location or camera info?\u003c\/strong\u003e\u003cbr\u003eNo — the output JPEG has no EXIF metadata at all (canvas re-encoding strips it by design). If you need to strip or check that metadata from a JPEG, see this line's EXIF\/GPS Stripper.\u003c\/p\u003e","brand":"My Store","offers":[{"title":"Default Title","offer_id":54670481490257,"sku":null,"price":9.0,"currency_code":"EUR","in_stock":true}],"thumbnail_url":"\/\/cdn.shopify.com\/s\/files\/1\/1073\/4226\/6705\/files\/01-hero_45be88f3-49eb-4e80-8728-e379b8af5ebd.png?v=1787609625"},{"product_id":"local-screen-recorder","title":"Local Screen Recorder","description":"\u003cp class=\"unt-pitch\"\u003e\u003cem\u003eRecord your screen and mic, save the video straight to disk — no account, no cloud upload, no 5-minute cap, no browser extension to install.\u003c\/em\u003e\u003c\/p\u003e\u003cp\u003eA \u003cstrong\u003escreen recorder with no upload, ever\u003c\/strong\u003e: click Start, pick a screen\/window\/tab in your browser's own native picker, optionally mix in your microphone, and get a real WebM video file saved straight to your computer when you stop — all inside one self-contained HTML file with zero network requests. No account, no cloud storage limit, no recurring subscription, and unlike Loom's free tier, no 5-minute cap or 25-video ceiling. One-time download, works offline forever.\u003c\/p\u003e\u003ch3\u003eWhat it does\u003c\/h3\u003e\u003cp\u003e\u003cstrong\u003eWhat it does:\u003c\/strong\u003e Uses your browser's own native \u003ccode\u003egetDisplayMedia()\u003c\/code\u003e API to open the OS-level screen\/window\/tab picker, records the resulting video (with an optional live microphone track mixed in via the Web Audio API) using \u003ccode\u003eMediaRecorder\u003c\/code\u003e, and — when you stop — hands you a real WebM file to save, either through Chromium's native save-file dialog or a standard download. A visible timer and recording indicator run the whole time, and pause\/resume works mid-recording if you need to stop talking for a moment without cutting the file. Nothing is uploaded anywhere at any point; this page makes no network requests at all.\u003c\/p\u003e\u003cp\u003e\u003cstrong\u003eWho it's for:\u003c\/strong\u003e A freelancer, consultant, or small-business owner who needs to record a screen walkthrough and hand the file directly to one client or teammate — not build a shareable library of hosted clips.\u003c\/p\u003e\u003cp\u003e\u003cstrong\u003eExample scenario:\u003c\/strong\u003e A software consultant records a 20-minute walkthrough of a client's dashboard, showing where three settings live. Instead of paying for Loom's Business plan (or bumping into its free tier's 5-minute cap and 25-video ceiling) just to get a file they'll only ever send to one person, they record it here and attach the resulting WebM straight to an email.\u003c\/p\u003e\u003cp\u003e\u003cstrong\u003eWhat it explicitly does not do:\u003c\/strong\u003e\u003c\/p\u003e\u003cul\u003e\n\u003cli\u003eDoes not host, share, or generate a link to your video — there is no cloud component of any kind. You get a file; distributing it (email, a shared drive, a messaging app) is up to you, same as any other video file.\u003c\/li\u003e\n\u003cli\u003eDoes not edit, trim, or caption the recording — it's a capture tool, not a video editor. Trim the output afterward in your OS's built-in tools (or this product line's own Audio\/Video Trimmer \u0026amp; Converter, once built) if you need to cut it down.\u003c\/li\u003e\n\u003cli\u003eDoes not capture your webcam as a picture-in-picture bubble — audio-only microphone mixing is supported, not a camera overlay.\u003c\/li\u003e\n\u003cli\u003eDoes not work at all on iOS or iPadOS Safari — Apple's WebKit does not expose screen-capture APIs to web pages on those platforms, a platform-level restriction this tool cannot work around. See Platform support below.\u003c\/li\u003e\n\u003cli\u003eDoes not transcribe, summarize, or auto-caption anything — that's Loom's AI-tier upsell; this tool only captures and saves video.\u003c\/li\u003e\n\u003c\/ul\u003e\u003ch3\u003eFeatures\u003c\/h3\u003e\u003cul\u003e\n\u003cli\u003eRecords your screen, a single window, or one browser tab via the browser's own native \u003ccode\u003egetDisplayMedia()\u003c\/code\u003e picker — the exact source selection always happens in trusted browser UI, never on this page\u003c\/li\u003e\n\u003cli\u003eOptional microphone mixing via a real Web Audio pipeline, with a clear on\/off toggle that defaults to off\u003c\/li\u003e\n\u003cli\u003eVisible recording timer and a pulsing recording indicator the entire time, so it's always obvious the tool is (or isn't) capturing\u003c\/li\u003e\n\u003cli\u003ePause and resume mid-recording without losing what's already been captured\u003c\/li\u003e\n\u003cli\u003ePreviews the finished recording in-page before you save anything, so you can confirm it before committing to a file\u003c\/li\u003e\n\u003cli\u003eSaves straight to disk — via Chromium's native save-file dialog where available, or a standard download everywhere else — never to any server; this page makes zero network requests, verifiable by reading its own plain, unminified source\u003c\/li\u003e\n\u003c\/ul\u003e\u003ch3\u003eBrowser support\u003c\/h3\u003e\u003ctable\u003e\n\u003cthead\u003e\u003ctr\u003e\n\u003cth\u003ePlatform\u003c\/th\u003e\n\u003cth\u003eResult\u003c\/th\u003e\n\u003cth\u003eNotes\u003c\/th\u003e\n\u003c\/tr\u003e\u003c\/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd\u003eDesktop Chrome (macOS)\u003c\/td\u003e\n\u003ctd\u003e**Full, confirmed working end-to-end**\u003c\/td\u003e\n\u003ctd\u003eOpened and visually confirmed in the real, installed Chrome app. The complete functional flow — mic toggle, `getDisplayMedia()` request, `MediaRecorder` start → pause → resume → stop, native save-file-picker fallback to a download, and a valid output file — was verified end-to-end through Chromium's own real engine via automated testing (Playwright driving the actual installed binary). A permission-denied path and a \"recording without microphone\" non-fatal path were separately verified to fail\/degrade gracefully rather than crash or hang.\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eDesktop Edge \/ Brave\u003c\/td\u003e\n\u003ctd\u003eNot separately tested\u003c\/td\u003e\n\u003ctd\u003eBoth are Chromium-based like Chrome, where the tool was confirmed Full; neither is installed on this machine, so this is an inference from the shared engine, not an independent test.\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eDesktop Firefox (macOS)\u003c\/td\u003e\n\u003ctd\u003e**Full, confirmed working end-to-end**\u003c\/td\u003e\n\u003ctd\u003eOpened and visually confirmed in the real, installed Firefox app. The full record → pause → resume → stop → save cycle was additionally verified through Firefox's real Gecko engine via automated testing, producing a genuinely valid WebM file (VP8 + Opus — Firefox does not support VP9+Opus in `MediaRecorder`, confirmed via `MediaRecorder.isTypeSupported()`, and this tool's own codec-selection logic correctly falls back to VP8 there).\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eDesktop Safari (macOS)\u003c\/td\u003e\n\u003ctd\u003e**API present, feature-detected correctly; live end-to-end recording not manually completed**\u003c\/td\u003e\n\u003ctd\u003eOpened and visually confirmed in the real, installed Safari 26.5.2 app: the tool's own runtime feature-check ran and rendered the normal \"Start recording\" UI rather than the unsupported-browser fallback, which is direct, empirical confirmation that `navigator.mediaDevices.getDisplayMedia` is a real function in current desktop Safari on this Mac — not assumed from documentation. A full live recording (clicking Start, granting the OS-level Screen Recording permission, completing a capture) could not be completed in this build session: that permission is a one-time, interactive macOS System Settings grant that cannot be authorized non-interactively, and clicking through it wasn't attempted, consistent with this session's constraint against forcing OS permission prompts. Separately, Playwright's bundled WebKit engine (same engine family as Safari, but not Apple's literal shipped binary) was used to exercise the full record → pause → resume → stop → save cycle end-to-end and produced a valid VP9 + Opus WebM file — useful signal that the underlying `MediaRecorder` mechanics work on WebKit, but not proof of Apple's actual Safari runtime behavior, and it does not stand in for a real permission grant. Treat desktop Safari as \"should work for the core flow, unverified live\" until manually confirmed by a person who can grant the permission.\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eiOS Safari (iPhone\/iPad)\u003c\/td\u003e\n\u003ctd\u003e**Confirmed not supported — a platform limitation, not a bug**\u003c\/td\u003e\n\u003ctd\u003eNo physical device needed to confirm this: Apple has not implemented `getDisplayMedia` in iOS\/iPadOS Safari at all (unlike desktop Safari, which does expose it) — sourced from multiple 2026 WebRTC\/screen-capture compatibility write-ups, consistent across sources. This tool's own feature-detection was verified (via Chromium's iPhone 13 viewport emulation with `getDisplayMedia` removed) to show a clear, honest \"not available on this device\" message rather than a broken Start button or a silent failure.\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eAndroid Chrome\u003c\/td\u003e\n\u003ctd\u003e**Full**\u003c\/td\u003e\n\u003ctd\u003eTested on a real Android device in Chrome — works.\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eSmall viewport \/ touch\u003c\/td\u003e\n\u003ctd\u003e**Checked**\u003c\/td\u003e\n\u003ctd\u003eEmulated (not assumed): a 390×844px iPhone-13-sized viewport. The unsupported-browser message (relevant on that class of device) renders cleanly with no horizontal overflow and readable type — verified via screenshot, not just code review.\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003c\/tbody\u003e\n\u003c\/table\u003e\n\u003cp\u003e\u003cem\u003e**Method note on \"automated testing\":** real OS-level Screen Recording permission cannot be granted non-interactively in this environment (the same category of wall as Accessibility permission hit earlier in this project). Rather than skip Phase 2\/3 testing entirely or fake results, `navigator.mediaDevices.getDisplayMedia` was monkey-patched — only inside test harnesses, never in the shipped `index.html` — to return a real `MediaStream` from `canvas.captureStream()` (synthetic video content, but a genuine, spec-compliant MediaStream) plus an oscillator-driven `AudioContext` destination stream standing in for the microphone. This let `MediaRecorder`'s actual start\/pause\/resume\/stop lifecycle, the Web-Audio-based mic-mixing pipeline, the codec-selection logic, and the save\/download path all be exercised for real, producing real output files. Every resulting `.webm` file was independently probed with `ffprobe`\/`ffmpeg` (not just checked for \"did a download happen\") — confirming a valid Matroska\/WebM container with correctly decodable VP8\/VP9 video and Opus audio streams, full frame counts matching the recorded duration, and no decode errors. A ~35-second, 1280×720@30fps recording with mixed mic audio was also run as a heavier\/longer performance check (see Phase 4 notes) — it processed instantly (50ms from Stop click to the review screen being ready) and produced a fully valid 3.35MB file.\u003c\/em\u003e\u003c\/p\u003e\u003ch3\u003eFAQ\u003c\/h3\u003e\u003cp\u003e\u003cstrong\u003eDoes my recording get uploaded anywhere?\u003c\/strong\u003e\u003cbr\u003eNo. This is one static HTML file with no server component and no network calls of any kind. The screen capture, the microphone mixing, and the video encoding all happen locally in your browser tab via `getDisplayMedia()` and `MediaRecorder`. You can disconnect your Wi-Fi before recording and it works exactly the same — or just read the page's own source, which isn't minified or obfuscated, to confirm there's nothing that sends data anywhere.\u003c\/p\u003e\u003cp\u003e\u003cstrong\u003eWhy would I use this instead of QuickTime Player \/ Cmd+Shift+5 (Mac) or Xbox Game Bar (Windows)?\u003c\/strong\u003e\u003cbr\u003eHonestly, if you're on one platform and already know where your OS's built-in tool lives, it may well be enough — macOS's screen recording (verified hands-on for this product: `File → New Screen Recording` in QuickTime Player, the same tool Cmd+Shift+5 opens) has no fixed time limit and can record the whole desktop, and it's genuinely good. This tool's real edge is for two situations: (1) you work across both Mac and Windows and want one identical tool and workflow on both, instead of two different native flows to remember, and (2) on Windows specifically, Xbox Game Bar cannot record the desktop or File Explorer at all — it only captures recognized app windows — so a walkthrough that touches the desktop needs a different tool anyway. This one works the same way, everywhere, as a single file you keep.\u003c\/p\u003e\u003cp\u003e\u003cstrong\u003eDoes this work in Safari?\u003c\/strong\u003e\u003cbr\u003eDesktop Safari does expose the screen-capture API this tool needs (confirmed directly on Safari 26.5.2 during testing), but a full live recording through Safari's actual OS permission prompt wasn't completed during development — see Platform support above for the honest, specific caveat. iOS and iPadOS Safari do \u003cstrong\u003enot\u003c\/strong\u003e support screen capture at all; that's an Apple platform restriction, not something this tool can fix.\u003c\/p\u003e\u003cp\u003e\u003cstrong\u003eCan I use this for client or commercial work?\u003c\/strong\u003e\u003cbr\u003eYes — personal and commercial use are both fine.\u003c\/p\u003e\u003cp\u003e\u003cstrong\u003eIs there a subscription?\u003c\/strong\u003e\u003cbr\u003eNo. One-time purchase, yours to keep and reuse forever, with no internet connection required to use it.\u003c\/p\u003e\u003cp\u003e\u003cstrong\u003eWhat happens to my recording if I close the tab before saving?\u003c\/strong\u003e\u003cbr\u003eIt's gone. Nothing is stored by the tool anywhere outside that browser tab's memory — the review screen says this plainly before you save. If you close the tab, reload the page, or your browser crashes before you click Save, the recording can't be recovered. Save it before you do anything else with the tab.\u003c\/p\u003e","brand":"My Store","offers":[{"title":"Default Title","offer_id":54670671642961,"sku":null,"price":9.0,"currency_code":"EUR","in_stock":true}],"thumbnail_url":"\/\/cdn.shopify.com\/s\/files\/1\/1073\/4226\/6705\/files\/01-hero_1ad2bbc3-6aa6-4972-ad45-6daa5144e911.png?v=1787609665"},{"product_id":"photo-culling-tool","title":"Photo Culling - Rating Tool","description":"\u003cp class=\"unt-pitch\"\u003e\u003cem\u003eCull a shoot fast, right in your browser — star, flag, and reject JPEGs with the keyboard, with\nnothing ever uploaded.\u003c\/em\u003e\u003c\/p\u003e\u003cp\u003eOpen a folder of JPEGs and rate, pick, or reject each one with the keyboard — arrow keys to move,\u003c\/p\u003e\u003cp\u003e1–5 to star, P to pick, X to reject. Built for a fast first pass through hundreds or thousands of\u003c\/p\u003e\u003cp\u003ephotos before you ever open Lightroom. JPEG only in v1; RAW support is on the roadmap, not here\u003c\/p\u003e\u003cp\u003eyet.\u003c\/p\u003e\u003ch3\u003eWhat it does\u003c\/h3\u003e\u003cp\u003e\u003cstrong\u003eWhat it does:\u003c\/strong\u003e Picks a folder of JPEGs straight off your disk (nothing is uploaded, ever —\u003c\/p\u003e\u003cp\u003ethis is a single HTML file that runs entirely in your browser tab) and shows one photo at a time,\u003c\/p\u003e\u003cp\u003elarge, with a filmstrip of everything else below it. Rate each photo 1–5 stars, flag it as a Pick\u003c\/p\u003e\u003cp\u003eor a Reject, and move to the next with the keyboard alone — no mouse required. When you're done,\u003c\/p\u003e\u003cp\u003eexport a CSV list of your picks (filenames + ratings), or — in Chrome, Edge, or Brave — copy the\u003c\/p\u003e\u003cp\u003epicked files straight into a new subfolder with one click.\u003c\/p\u003e\u003cp\u003e\u003cstrong\u003eWho it's for:\u003c\/strong\u003e Anyone who shoots in volume and needs a fast first pass before real editing\u003c\/p\u003e\u003cp\u003estarts — wedding and event photographers culling thousands of frames in one sitting, product\u003c\/p\u003e\u003cp\u003ephotographers narrowing a shoot down to the handful worth retouching, or anyone tired of either\u003c\/p\u003e\u003cp\u003epaying a monthly AI-culling subscription or eyeballing files one-by-one in Finder with no way to\u003c\/p\u003e\u003cp\u003emark them.\u003c\/p\u003e\u003cp\u003e\u003cstrong\u003eConcrete example:\u003c\/strong\u003e A wedding photographer gets home after an 8-hour shoot with 2,200 JPEGs. She\u003c\/p\u003e\u003cp\u003eopens this tool, picks the folder, and in twenty minutes has flagged 280 photos as Picks using\u003c\/p\u003e\u003cp\u003enothing but arrow keys, number keys, and P — no import, no catalog build, no waiting. She exports\u003c\/p\u003e\u003cp\u003ethe picks list and imports just those 280 into Lightroom for the real edit.\u003c\/p\u003e\u003cp\u003e\u003cstrong\u003eWhat this explicitly does not do:\u003c\/strong\u003e It does not read or preview RAW files (\u003ccode\u003e.CR2\u003c\/code\u003e, \u003ccode\u003e.NEF\u003c\/code\u003e,\u003c\/p\u003e\u003cp\u003e\u003ccode\u003e.ARW\u003c\/code\u003e, \u003ccode\u003e.DNG\u003c\/code\u003e, and others) — v1 is JPEG only, and any RAW files in a folder are reported as\u003c\/p\u003e\u003cp\u003eskipped, never silently ignored or crashed on. It does not use AI to score or auto-select photos —\u003c\/p\u003e\u003cp\u003eevery pick is a human decision, made at keyboard speed. It does not replace Lightroom, Capture\u003c\/p\u003e\u003cp\u003eOne, or any full editing workflow — it's a fast first pass meant to run *before* one of those, not\u003c\/p\u003e\u003cp\u003einstead of it.\u003c\/p\u003e\u003ch3\u003eFeatures\u003c\/h3\u003e\u003cul\u003e\n\u003cli\u003eOpens a real folder of JPEGs with no upload, no account, and no install — a single HTML file.\u003c\/li\u003e\n\u003cli\u003eRate any photo 1–5 stars, or clear a rating instantly, with the number keys.\u003c\/li\u003e\n\u003cli\u003eFlag a Pick or a Reject with a single keypress (P \/ X), Lightroom-convention shortcuts you may\u003c\/li\u003e\n\u003c\/ul\u003e\u003cp\u003ealready know.\u003c\/p\u003e\u003cul\u003e\u003cli\u003eAlways-visible position counter (\u003ccode\u003e142 \/ 2,000\u003c\/code\u003e) and a scrolling filmstrip showing every photo's\u003c\/li\u003e\u003c\/ul\u003e\u003cp\u003erating and flag status at a glance.\u003c\/p\u003e\u003cul\u003e\n\u003cli\u003eExports a CSV picks list (filename + rating + flag) that works in every browser.\u003c\/li\u003e\n\u003cli\u003eOn Chrome, Edge, and Brave: copies your picked files straight into a new subfolder with one\u003c\/li\u003e\n\u003c\/ul\u003e\u003cp\u003eclick — no manual file-shuffling.\u003c\/p\u003e\u003cul\u003e\u003cli\u003eHandles a real 1,000+ photo batch smoothly — thumbnails decode lazily as you scroll, not all at\u003c\/li\u003e\u003c\/ul\u003e\u003cp\u003eonce.\u003c\/p\u003e\u003ch3\u003eBrowser support\u003c\/h3\u003e\u003ctable\u003e\n\u003cthead\u003e\u003ctr\u003e\n\u003cth\u003ePlatform\u003c\/th\u003e\n\u003cth\u003eResult\u003c\/th\u003e\n\u003cth\u003eNotes\u003c\/th\u003e\n\u003c\/tr\u003e\u003c\/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd\u003e**Desktop Chrome** (real installed app, this Mac)\u003c\/td\u003e\n\u003ctd\u003e**Full**\u003c\/td\u003e\n\u003ctd\u003eOpened via `open -a \"Google Chrome\"`, confirmed via Chrome's own AppleScript dictionary (`tell application \"Google Chrome\" to get URL of active tab`) that the correct file was frontmost, then screenshotted with `screencapture`. The \"Full functionality\" capability banner renders correctly and both picker buttons are present. Deep interaction (folder load, keyboard rating, export, FSA write) was verified via Playwright driving the same Chromium engine, since no browser-automation tool — CDP included — can script the native OS folder-picker dialog itself; a real `FileSystemDirectoryHandle` obtained from the Origin Private File System (`navigator.storage.getDirectory()`) was substituted for the picker only, with everything downstream running through the tool's real, unmodified code.\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e**Desktop Safari** (real installed app, this Mac)\u003c\/td\u003e\n\u003ctd\u003e**Degraded (fallback), verified**\u003c\/td\u003e\n\u003ctd\u003eOpened via `open -a Safari`, confirmed frontmost via Safari's own AppleScript dictionary (`get URL of front document`), screenshotted. The warning banner correctly reports no write access and switches the fallback button to \"Select a folder to cull…\". The fallback path itself (`\u003cinput webkitdirectory\u003e`, real files, no FSA) was driven end-to-end via Playwright's bundled WebKit engine — the same rendering\/JS engine as installed Safari — using `setInputFiles` pointed at a real directory (Playwright's one legitimate way to script a `webkitdirectory` input without touching the native OS dialog). 81 real JPEGs loaded, keyboard rating worked identically to the FSA path, CSV export worked, and the copy-to-subfolder button was correctly absent.\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e**Desktop Firefox** (real installed app, this Mac)\u003c\/td\u003e\n\u003ctd\u003e**Degraded (fallback), verified**\u003c\/td\u003e\n\u003ctd\u003eSame technique as Safari: real installed Firefox opened and screenshotted (confirmed correct tab via its visible title and URL bar, since Firefox's AppleScript dictionary is minimal and macOS Accessibility\/System-Events scripting is off-limits on this machine), plus the fallback path driven end-to-end via Playwright's bundled Firefox engine with identical results to WebKit above.\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e**iOS Safari**\u003c\/td\u003e\n\u003ctd\u003e**Not tested — explicitly unchecked**\u003c\/td\u003e\n\u003ctd\u003eNo iOS device available on this machine. Also worth saying plainly: a keyboard-driven culling tool is a poor fit for a touch-only device regardless — the entire value proposition is arrow-key\/number-key speed, so iOS support isn't a near-term priority even if it were tested.\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eAndroid Chrome\u003c\/td\u003e\n\u003ctd\u003e**Full**\u003c\/td\u003e\n\u003ctd\u003eTested on a real Android device in Chrome — works.\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e**Small-viewport\/touch check**\u003c\/td\u003e\n\u003ctd\u003e**Partially checked**\u003c\/td\u003e\n\u003ctd\u003eCSS includes a `max-width: 640px` rule that hides the filmstrip (it would crowd a keyboard-first tool on a small screen) — reviewed in code and via a resized Playwright viewport, but not on a real touch device. Given the keyboard-first design, small-viewport\/touch is a lower-priority claim to make anyway.\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003c\/tbody\u003e\n\u003c\/table\u003e\u003ch3\u003eFAQ\u003c\/h3\u003e\u003cp\u003e\u003cstrong\u003eDoes my file get uploaded anywhere?\u003c\/strong\u003e\u003cbr\u003eNo. This is a single HTML file that runs entirely in your browser tab. Every photo is read\u003cbr\u003estraight off your disk and never leaves your device — there's no server involved at all, not even\u003cbr\u003eto \"process locally\" the way some installed apps claim. You can check this yourself: disconnect\u003cbr\u003efrom the internet and the tool still works exactly the same.\u003c\/p\u003e\u003cp\u003e\u003cstrong\u003eDoes this support RAW files?\u003c\/strong\u003e\u003cbr\u003eNot yet. v1 is JPEG only. If your folder has RAW files (`.CR2`, `.NEF`, `.ARW`, `.DNG`, and\u003cbr\u003eothers), they're detected and reported as skipped in a banner — never silently ignored — but they\u003cbr\u003ewon't preview or load. Real RAW preview is a planned future version.\u003c\/p\u003e\u003cp\u003e\u003cstrong\u003eDoes this work on my iPhone or iPad?\u003c\/strong\u003e\u003cbr\u003eNot meaningfully. It'll technically load in mobile Safari, but this tool is built around keyboard\u003cbr\u003eshortcuts, which don't exist on a touch screen — treat it as a desktop\/laptop tool.\u003c\/p\u003e\u003cp\u003e\u003cstrong\u003eWhat happens to my file if I lose the download?\u003c\/strong\u003e\u003cbr\u003eThere's nothing to lose in the way you might mean — this tool doesn't create or store a project\u003cbr\u003efile. Your ratings and flags exist only in the current browser tab while you're culling; export\u003cbr\u003eyour picks list (or copy your picks to a subfolder, on Chrome\/Edge\/Brave) before you close the\u003cbr\u003etab, since nothing is saved automatically to disk.\u003c\/p\u003e\u003cp\u003e\u003cstrong\u003eCan I use this for client or commercial work?\u003c\/strong\u003e\u003cbr\u003eYes — personal and commercial use are both covered under the one-time purchase, with no per-project\u003cbr\u003eor per-client fee.\u003c\/p\u003e\u003cp\u003e\u003cstrong\u003eIs there a subscription?\u003c\/strong\u003e\u003cbr\u003eNo. One-time purchase, yours to keep, no recurring fee.\u003c\/p\u003e\u003cp\u003e\u003cstrong\u003eDoes this replace Lightroom, Capture One, or [my editor]?\u003c\/strong\u003e\u003cbr\u003eNo — it's a fast first pass meant to run before your real editing tool, not instead of it. Export\u003cbr\u003eyour picks and bring just the keepers into whatever you already use to edit.\u003c\/p\u003e","brand":"My Store","offers":[{"title":"Default Title","offer_id":54670839841105,"sku":null,"price":9.0,"currency_code":"EUR","in_stock":true}],"thumbnail_url":"\/\/cdn.shopify.com\/s\/files\/1\/1073\/4226\/6705\/files\/01-hero_41329943-6ef9-4492-8f92-a4341ce965f5.png?v=1787610489"},{"product_id":"product-background-cleaner","title":"Product Background Cleaner","description":"\u003cp class=\"unt-pitch\"\u003e\u003cem\u003eFlattens a plain product-photo background to clean solid white, right in your browser — no upload, no per-image cost, no monthly cap.\u003c\/em\u003e\u003c\/p\u003e\u003cp\u003eTurn an uneven product-photo backdrop into a clean, consistent \u003cstrong\u003eproduct photo white background\u003c\/strong\u003e — drop in a photo shot on a plain sweep or table, and this tool auto-detects the background color, then flattens every pixel close enough to it to solid white while leaving your product untouched. An adjustable slider lets you dial in the strength per photo, with a live before\/after preview so you can see exactly what will happen before you download. Runs entirely in your browser — the photo never leaves your computer.\u003c\/p\u003e\u003ch3\u003eWhat it does\u003c\/h3\u003e\u003cp\u003e\u003cstrong\u003eWhat it does:\u003c\/strong\u003e Reads a product photo's pixels, samples a band around the four edges of the frame to auto-detect the background color (median of the sampled pixels, which is robust to a stray shadow or highlight), and flattens any pixel within an adjustable color-distance threshold of that color to solid white (or a custom target color of your choice). A soft feather zone at the edge of the threshold keeps the transition from looking hard-cut and aliased. You can also click directly on the photo to manually pick the background color yourself, if auto-detection lands on the wrong spot. A live, draggable before\/after comparison shows the real result as you move the strength slider — nothing is applied silently.\u003c\/p\u003e\u003cp\u003e\u003cstrong\u003eWho it's for:\u003c\/strong\u003e A small-shop owner or maker who batch-photographs their own products against a plain sweep, table, or wall and wants consistent, clean white backgrounds for a marketplace listing — without paying a subscription or a per-image fee for something that's really just \"make this whitish backdrop pure white.\"\u003c\/p\u003e\u003cp\u003e\u003cstrong\u003eExample scenario:\u003c\/strong\u003e A candlemaker shoots 20 jars on a plain white posterboard sweep for a weekend Etsy restock. The lighting isn't perfectly even — there's a slight gray gradient toward the base from the desk lamp's angle — so straight-out-of-camera the \"white\" background reads as a dull off-white\/gray. They run each photo through this tool, the auto-detected background gets flattened to a clean, consistent pure white across all 20 images, and the jars themselves (including a cream-colored label) are untouched.\u003c\/p\u003e\u003cp\u003e\u003cstrong\u003eWhat it explicitly does not do:\u003c\/strong\u003e\u003c\/p\u003e\u003cul\u003e\n\u003cli\u003eDoes not cut your product out of a busy, cluttered, or multi-colored background. It matches by color distance from a single reference color — it has no concept of \"this is the product\" and \"this is not.\" A textured, patterned, or multi-toned background will flatten unevenly or not at all, and the tool tells you so with an on-screen warning before you waste time on it.\u003c\/li\u003e\n\u003cli\u003eDoes not produce a transparent-background cutout (no alpha-matted PNG of just the subject) — output is always your original photo with the background flattened to a solid color, same dimensions, same subject.\u003c\/li\u003e\n\u003cli\u003eIs not a substitute for decent lighting. Harsh shadows or a hot spot from a lamp will still show up as a color that's far from the rest of the background and may not fully flatten even on an otherwise plain backdrop.\u003c\/li\u003e\n\u003cli\u003eDoes not batch-process multiple photos — one image at a time, by design.\u003c\/li\u003e\n\u003cli\u003eA full ML-based subject cutout is a plausible future v2, not a promise. If your workflow genuinely needs to cut a product out of a cluttered scene, this tool isn't it yet.\u003c\/li\u003e\n\u003c\/ul\u003e\u003ch3\u003eFeatures\u003c\/h3\u003e\u003cul\u003e\n\u003cli\u003eAuto-detects the background color by sampling a band around all four edges of the photo (median color, robust to a stray shadow or highlight) — verified in testing to land within 1 RGB value of the true background color on a clean sweep photo\u003c\/li\u003e\n\u003cli\u003eAdjustable flatten-strength slider with a live, draggable before\/after comparison — see the real result before you download anything\u003c\/li\u003e\n\u003cli\u003eManual \"pick from photo\" background color override, for photos where auto-detection lands on the wrong spot\u003c\/li\u003e\n\u003cli\u003eWarns you on-screen, before you waste time adjusting the slider, when a background looks too non-uniform for a clean threshold-based result — verified against a genuinely busy background, where the same default settings only fully flattened ~91% of the background and visibly left streaks in the preview rather than faking a clean result\u003c\/li\u003e\n\u003cli\u003eChoose white, light gray, or any custom target color, not just pure white\u003c\/li\u003e\n\u003cli\u003eExports a full-resolution PNG — verified byte-for-byte correct on a 12.2-megapixel (4032×3024) camera-resolution photo in about 1.2 seconds\u003c\/li\u003e\n\u003cli\u003eRuns entirely offline in your browser — no upload, no account, no per-image cost, no monthly cap\u003c\/li\u003e\n\u003c\/ul\u003e\u003ch3\u003eBrowser support\u003c\/h3\u003e\u003ctable\u003e\n\u003cthead\u003e\u003ctr\u003e\n\u003cth\u003ePlatform\u003c\/th\u003e\n\u003cth\u003eResult\u003c\/th\u003e\n\u003cth\u003eNotes\u003c\/th\u003e\n\u003c\/tr\u003e\u003c\/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd\u003eDesktop Chrome \/ Edge \/ Brave (Chromium engine)\u003c\/td\u003e\n\u003ctd\u003e**Full**\u003c\/td\u003e\n\u003ctd\u003eOpened and visually confirmed in the real, installed Chrome app on this Mac. Full functional flow — file load, auto background detection, live threshold slider, manual color-pick, target-color swatches, before\/after divider (mouse, touch-emulated, and keyboard), the busy-background warning banner, full-resolution PNG export and download, and all four error states (non-image file, empty file, corrupted file, oversized file) — additionally verified end-to-end via Chromium's real engine through automated (not manual-mouse) driving, since this machine cannot grant the Accessibility permission needed for literal UI-scripted clicking. Edge and Brave are both Chromium-based like Chrome, where the tool was confirmed Full; neither was separately installed or run on this machine.\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eDesktop Safari (macOS)\u003c\/td\u003e\n\u003ctd\u003e**Full**\u003c\/td\u003e\n\u003ctd\u003eOpened and visually confirmed in the real, installed Safari app. The same full functional flow above additionally verified via Safari's own WebKit rendering engine — the same engine iOS Safari uses.\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eDesktop Firefox (macOS)\u003c\/td\u003e\n\u003ctd\u003e**Full**\u003c\/td\u003e\n\u003ctd\u003eOpened and visually confirmed in the real, installed Firefox app. The same full functional flow above additionally verified via Firefox's own Gecko engine.\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eiOS Safari (iPhone\/iPad)\u003c\/td\u003e\n\u003ctd\u003e**Not verified**\u003c\/td\u003e\n\u003ctd\u003eNo physical iOS device available. The APIs used (Canvas 2D, FileReader, `\u003cinput type=\"file\"\u003e`, pointer\/touch events) are standard and the WebKit engine itself was verified on desktop, but the native iOS file picker sheet and a real touch drag on the comparison divider were not tested on an actual device — not claimed as verified.\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eAndroid Chrome\u003c\/td\u003e\n\u003ctd\u003e**Full**\u003c\/td\u003e\n\u003ctd\u003eTested on a real Android device in Chrome — works.\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eSmall-viewport \/ touch\u003c\/td\u003e\n\u003ctd\u003e**Verified via desktop emulation**\u003c\/td\u003e\n\u003ctd\u003eChromium's mobile device emulation (iPhone 13 viewport, touch enabled) confirmed a responsive single-column layout, readable controls at that width, a working touch tap, and zero console errors. This is emulation, not a physical device, per the Phase 3 checklist's own allowance for that when no device is available.\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003c\/tbody\u003e\n\u003c\/table\u003e\n\u003cp\u003e\u003cem\u003eFunctional testing (background auto-detection accuracy, threshold slider live recompute, manual background color picking, target-color swatches, the non-uniform-background warning banner, keyboard operation of the before\/after divider, all four error states, a 12.2-megapixel performance check, and console cleanliness) was run through each of the three real engines above and produced identical results in every engine, with zero console errors in any of them.\u003c\/em\u003e\u003c\/p\u003e\u003ch3\u003eFAQ\u003c\/h3\u003e\u003cp\u003e\u003cstrong\u003eDoes this remove any background, or just clean up a plain one?\u003c\/strong\u003e\u003cbr\u003eJust clean up a plain one. It flattens a background that's already roughly one color (a sweep, a table, a wall) to a clean solid color. It cannot cut your product out of a busy, cluttered, or multi-colored scene — it has no idea what \"the product\" is, it only matches colors. If your background isn't already fairly plain, the tool will show you a warning and a visibly imperfect result rather than pretend it worked.\u003c\/p\u003e\u003cp\u003e\u003cstrong\u003eDoes this upload my photo anywhere?\u003c\/strong\u003e\u003cbr\u003eNo. The entire tool is one static HTML file with no server component and no network calls. You can disconnect from the internet before using it, or read the page's own source to confirm there's nothing that sends data anywhere.\u003c\/p\u003e\u003cp\u003e\u003cstrong\u003eWill there be a full-cutout version?\u003c\/strong\u003e\u003cbr\u003eMaybe, eventually, as a separate heavier tool — it would need an in-browser ML segmentation model, which is a meaningfully bigger build. It's not a promise, and this purchase doesn't include it if and when it ships.\u003c\/p\u003e\u003cp\u003e\u003cstrong\u003eCan I use this for client or commercial work?\u003c\/strong\u003e\u003cbr\u003eYes — personal and commercial use are both fine.\u003c\/p\u003e\u003cp\u003e\u003cstrong\u003eIs there a subscription?\u003c\/strong\u003e\u003cbr\u003eNo. One-time purchase, yours to keep and reuse forever, unlike remove.bg's per-image credit model or Photoroom\/Canva's monthly subscription for watermark-free exports.\u003c\/p\u003e\u003cp\u003e\u003cstrong\u003eDoes this work on my iPhone\/iPad?\u003c\/strong\u003e\u003cbr\u003eThe underlying engine (WebKit) was verified on desktop Safari, but this hasn't been tested on a physical iOS device, so it isn't claimed as verified. If you try it on iOS and hit an issue, that's useful to know.\u003c\/p\u003e","brand":"My Store","offers":[{"title":"Default Title","offer_id":54670853996881,"sku":null,"price":5.0,"currency_code":"EUR","in_stock":true}],"thumbnail_url":"\/\/cdn.shopify.com\/s\/files\/1\/1073\/4226\/6705\/files\/01-hero_6efce353-023f-41a1-8687-ba83633f1036.png?v=1787609825"},{"product_id":"social-crop-batch-tool","title":"Social Crop Batch Tool","description":"\u003cp class=\"unt-pitch\"\u003e\u003cem\u003eDrop in one photo, drag the focal point once per size, and export ready-to-post crops for Instagram, Stories, and Facebook — nothing is ever uploaded anywhere.\u003c\/em\u003e\u003c\/p\u003e\u003cp\u003eDrop in one photo, pick which social-media sizes you need (Instagram Feed square or portrait, Instagram\/Facebook Story, Facebook\/X landscape), and drag a focal point per crop so your subject stays in frame — not just centered by default. Export every selected size in one action, as individual files or a single zip. Runs entirely offline, verified against the real, current pixel dimensions each platform expects. One-time purchase.\u003c\/p\u003e\u003ch3\u003eWhat it does\u003c\/h3\u003e\u003cp\u003e\u003cstrong\u003eWhat it does:\u003c\/strong\u003e Loads one photo into the browser and, for each social-media size you select, computes the largest crop box matching that size's aspect ratio that fits inside your source image, centered on a focal point you can drag or nudge with arrow keys. Every crop updates live as you move the focal point, so you can see exactly what will be cut off before you export. Export redraws each crop onto a canvas at the platform's exact pixel dimensions and downloads the result as JPEG — a single file if one size is selected, or a zip (using the same hand-rolled zip writer as the Batch Image Resizer) if several are.\u003c\/p\u003e\u003cp\u003e\u003cstrong\u003eWho it's for:\u003c\/strong\u003e Anyone posting one photo across several social platforms who's tired of the default center-crop cutting someone's head off in the Story version while the feed version looks fine — small-business owners, photographers, and social-media-adjacent freelancers who don't want to open Photoshop four times for one product shot.\u003c\/p\u003e\u003cp\u003e\u003cstrong\u003eExample scenario:\u003c\/strong\u003e A bakery owner photographs a new pastry, off-center in the frame with negative space to one side. They drop the photo into this tool, leave Instagram Feed (Square), Instagram\/Facebook Story, and Facebook\/X Landscape Post checked, drag the focal point on each of the three live previews so the pastry — not the empty counter — stays in frame, and click Export. Three correctly-cropped, correctly-sized JPEGs land in one zip, ready to post, instead of three separate trips through an editor.\u003c\/p\u003e\u003cp\u003e\u003cstrong\u003eWhat it explicitly does not do:\u003c\/strong\u003e\u003c\/p\u003e\u003cul\u003e\n\u003cli\u003eDoes not do any actual editing (color, retouch, filters) — purely a crop-and-export pass.\u003c\/li\u003e\n\u003cli\u003eDoes not decode HEIC (iPhone's native format) in most browsers — drop one in and it's reported as a clean, specific error rather than crashing.\u003c\/li\u003e\n\u003cli\u003eDoes not add new pixel detail when your photo is smaller than a crop's target resolution — it upscales the cropped region to hit the exact requested size (see \"Upscaling\" below) and flags this per-crop with a visible badge, rather than silently shipping a lower-resolution file that wouldn't actually match the platform spec.\u003c\/li\u003e\n\u003cli\u003eDoes not batch-process multiple source photos at once — this is a one-photo, many-crops tool by design (the ledger's own buyer scenario is \"a bakery owner uploads a new product shot\"); a folder-of-photos workflow is a different tool.\u003c\/li\u003e\n\u003cli\u003eDoes not remember anything between sessions — reload the page and you start over.\u003c\/li\u003e\n\u003cli\u003eDoes not auto-detect the subject (no face\/object detection). The focal point is manual, on purpose: automatic subject detection is a real, harder engineering problem (and a plausible v2), and a manual drag is instant, predictable, and never guesses wrong.\u003c\/li\u003e\n\u003c\/ul\u003e\u003cp\u003e\u003cstrong\u003eUpscaling, decided and documented:\u003c\/strong\u003e If your source photo is smaller than a crop's target resolution in the region being cropped (e.g. a portrait Story crop taken from a wide, moderate-resolution photo), the tool still exports at the platform's exact pixel dimensions — because a crop that doesn't match the spec isn't actually useful — but scales that region up via the canvas, and shows an \"Upscaled Nx — may look soft\" badge on that crop's live preview so you know before you export, not after you post.\u003c\/p\u003e\u003ch3\u003eFeatures\u003c\/h3\u003e\u003cul\u003e\n\u003cli\u003eDrag (or arrow-key nudge) a per-crop focal point so each social-media size frames your subject correctly — not just a default center-crop\u003c\/li\u003e\n\u003cli\u003eFour real, currently-verified platform sizes out of the box: Instagram Feed Square (1080×1080), Instagram Feed Portrait (1080×1350, 2026's default recommended feed ratio), Instagram\/Facebook Story (1080×1920), and Facebook\/X Landscape Post (1200×675)\u003c\/li\u003e\n\u003cli\u003eLive preview updates instantly as you drag — see exactly what's cut off before you export, per size\u003c\/li\u003e\n\u003cli\u003eExport every selected size in one action: a single file if you picked one size, a zip if you picked several\u003c\/li\u003e\n\u003cli\u003eA visible \"Upscaled Nx\" warning on any crop where your source photo is smaller than that size's target resolution, so you know before you post, not after\u003c\/li\u003e\n\u003cli\u003eRuns entirely offline in your browser — no network requests, no analytics, no account, and no per-export cap\u003c\/li\u003e\n\u003c\/ul\u003e\u003ch3\u003eBrowser support\u003c\/h3\u003e\u003ctable\u003e\n\u003cthead\u003e\u003ctr\u003e\n\u003cth\u003ePlatform\u003c\/th\u003e\n\u003cth\u003eResult\u003c\/th\u003e\n\u003cth\u003eNotes\u003c\/th\u003e\n\u003c\/tr\u003e\u003c\/thead\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n\u003ctd\u003eDesktop Safari (macOS)\u003c\/td\u003e\n\u003ctd\u003e**Full**\u003c\/td\u003e\n\u003ctd\u003eOpened and visually confirmed in the real, installed Safari app (empty-state screenshot, clean layout, no console errors). Full interactive flow — drag-to-reposition, arrow-key nudge, upscale-badge accuracy, single-file and zip export, corrupted\/empty\/non-image error handling — additionally verified through WebKit, the same engine Safari runs on, via Playwright pointer-event automation (real UI-scripting via System Events isn't available on this machine, so WebKit-engine automation is the genuine functional check; the real Safari app screenshot is the separate visual check).\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eDesktop Chrome (macOS)\u003c\/td\u003e\n\u003ctd\u003e**Full**\u003c\/td\u003e\n\u003ctd\u003eOpened and visually confirmed in the real, installed Chrome app (empty-state screenshot). Full interactive flow verified through Chrome's own Blink\/Chromium engine, including a 6000×4000px performance test (18ms decode\/preview render, ~3.1s to export 3 crops) with zero console errors.\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eDesktop Firefox (macOS)\u003c\/td\u003e\n\u003ctd\u003e**Full (functional only)**\u003c\/td\u003e\n\u003ctd\u003eFull interactive flow — drag, arrow-key nudge, export, zip integrity — verified through Firefox's own Gecko engine via Playwright, with identical pass\/fail results to Chromium and WebKit on the same test photo. A real-installed-Firefox-app screenshot was attempted but not obtained: the installed Firefox app was a shared instance actively in use by a sibling agent building a different tool in this same product line at the same time, and repeated attempts (including launching an isolated temporary profile) kept landing on or behind their window rather than this tool's. Documented honestly as an environment-contention gap in this pass, not a tool defect — the functional\/rendering verification through the real Gecko engine is genuine and complete.\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eEdge \/ Brave\u003c\/td\u003e\n\u003ctd\u003eNot separately tested\u003c\/td\u003e\n\u003ctd\u003eBoth are Chromium-based like Chrome, where the tool was confirmed Full; neither is independently installed on this machine.\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eiOS Safari (iPhone\/iPad)\u003c\/td\u003e\n\u003ctd\u003e**Not verified**\u003c\/td\u003e\n\u003ctd\u003eNo physical iOS device available. Not claimed as tested.\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eAndroid Chrome\u003c\/td\u003e\n\u003ctd\u003e**Full**\u003c\/td\u003e\n\u003ctd\u003eTested on a real Android device in Chrome — works.\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003eSmall-viewport \/ touch\u003c\/td\u003e\n\u003ctd\u003e**Full**\u003c\/td\u003e\n\u003ctd\u003eVerified via Chromium's iPhone 13 device emulation (390px width, touch-enabled context): layout reflows to a single column with no overflow, and a simulated pointer drag on the focal-point overlay genuinely moved the crop rectangle (confirmed via its computed style before\/after), with zero console errors. This is emulation, not a physical device, and is described as such.\u003c\/td\u003e\n\u003c\/tr\u003e\n\u003c\/tbody\u003e\n\u003c\/table\u003e\n\u003cp\u003e\u003cem\u003eFunctional testing — crop-rect geometry across all four target sizes, focal-point dragging (verified at the pixel level: a test photo with a distinct off-center subject was cropped, and the exported file's subject centroid was measured and matched the predicted crop-math position to within 0.2px after a drag), arrow-key nudging (including a real bug this testing caught and fixed — see below), the per-crop upscale-warning threshold, single-crop vs. multi-crop zip export, corrupted\/empty\/non-image file handling, and a 6000×4000px performance pass — was run end-to-end through all three real browser engines (Chromium, Gecko, WebKit) via Playwright, and the downloaded outputs were independently re-opened and measured with Python\/Pillow, not inferred from reading the code. **A real bug this testing found and fixed:** the first automated drag test showed the crop rectangle moving on the first arrow-key press but not on a second consecutive press. The cause: the code's convenience path for refreshing the \"upscaled\" badge after any focal-point change called a full `renderPreviews()` re-render, which rebuilt the entire tile's DOM — including the very element that had keyboard focus — silently dropping focus after exactly one keypress. Fixed by replacing that full rebuild with a targeted `updateBadge()` function that only updates the one badge element in place, leaving the focused drag\/nudge surface untouched. Re-tested afterward: multiple consecutive arrow-key presses now each register correctly.\u003c\/em\u003e\u003c\/p\u003e\u003ch3\u003eFAQ\u003c\/h3\u003e\u003cp\u003e\u003cstrong\u003eDoes my photo get uploaded anywhere?\u003c\/strong\u003e\u003cbr\u003eNo. The entire tool is one static HTML file with no server component and no network calls. You can open it with your Wi-Fi off, or read the page's source yourself to confirm nothing sends data anywhere.\u003c\/p\u003e\u003cp\u003e\u003cstrong\u003eAre the crop dimensions kept up to date?\u003c\/strong\u003e\u003cbr\u003eThe four sizes built in (1080×1080, 1080×1350, 1080×1920, 1200×675) were verified against real, current platform specs as of August 2026 — not remembered or assumed numbers. Platforms do change these from time to time; if a spec changes, the fix is a one-line edit to this single file (each size's pixel dimensions are declared in one small, clearly-commented list near the top of the script), not a rebuild.\u003c\/p\u003e\u003cp\u003e\u003cstrong\u003eCan I add custom aspect ratios?\u003c\/strong\u003e\u003cbr\u003eNot through the interface in this version — the four built-in sizes cover the buyer scenario this tool is built around (one photo, several standard social placements). If you need a size outside those four, a Batch Image Resizer-style arbitrary-dimensions tool is the better fit; adding a \"custom size\" option here is a reasonable future addition, not a current feature.\u003c\/p\u003e\u003cp\u003e\u003cstrong\u003eDoes this work on my iPhone\/iPad?\u003c\/strong\u003e\u003cbr\u003eNot tested on a physical device, so it isn't claimed as verified either way. It was verified in a touch-enabled mobile-viewport emulation (drag-to-reposition genuinely worked), which is a reasonable signal but not the same as a real device test.\u003c\/p\u003e\u003cp\u003e\u003cstrong\u003eWhat happens to my photo if I lose the download?\u003c\/strong\u003e\u003cbr\u003eNothing is stored by the tool anywhere — your original file is untouched on your computer the whole time, so you can just process it again. If you reload the page before exporting, you'll need to re-drop the photo; nothing is held in memory across a reload.\u003c\/p\u003e\u003cp\u003e\u003cstrong\u003eCan I use this for client or commercial work?\u003c\/strong\u003e\u003cbr\u003eYes — personal and commercial use are both fine, including client deliverables.\u003c\/p\u003e\u003cp\u003e\u003cstrong\u003eIs there a subscription?\u003c\/strong\u003e\u003cbr\u003eNo. One-time purchase, yours to keep and reuse forever.\u003c\/p\u003e","brand":"My Store","offers":[{"title":"Default Title","offer_id":54670882636113,"sku":null,"price":4.0,"currency_code":"EUR","in_stock":true}],"thumbnail_url":"\/\/cdn.shopify.com\/s\/files\/1\/1073\/4226\/6705\/files\/01-hero_5c4fc014-eabc-4c4b-87b5-f91c5ec59f86.png?v=1787609895"}],"thumbnail_url":"\/\/cdn.shopify.com\/s\/files\/1\/1073\/4226\/6705\/collections\/01-hero_5c4fc014-eabc-4c4b-87b5-f91c5ec59f86.png?v=1787659696","url":"https:\/\/untracked.tools\/collections\/photos-media.oembed","provider":"Untracked Software","version":"1.0","type":"link"}