clone

a photo toolkit for your phone that never uploads: fuji film looks for raw files, social crops, error level analysis

main
gudpics / home.mjs
home.mjs 2.7K
1// SPDX-License-Identifier: AGPL-3.0-or-later2const $=id=>document.getElementById(id);3const standalone=matchMedia('(display-mode: standalone)').matches||navigator.standalone===true;4const ios=/iPad|iPhone|iPod/.test(navigator.userAgent)||(navigator.platform==='MacIntel'&&navigator.maxTouchPoints>1);5let installPrompt;6window.addEventListener('beforeinstallprompt',e=>{e.preventDefault();installPrompt=e;if(!standalone)$('install').hidden=false;});7$('install').onclick=async()=>{await installPrompt?.prompt();installPrompt=null;$('install').hidden=true;};8if(ios&&!standalone)$('install-ios').hidden=false;9$('install-ios').onclick=()=>{$('info').showModal();$('install-help').scrollIntoView({block:'center'});};10$('about').onclick=()=>$('info').showModal();11$('close-info').onclick=()=>$('info').close();12$('info').onclick=e=>{if(e.target===$('info'))$('info').close();};13if('serviceWorker'in navigator){14 let hadController=Boolean(navigator.serviceWorker.controller);navigator.serviceWorker.addEventListener('controllerchange',()=>{if(hadController)location.reload();hadController=true;});15 navigator.serviceWorker.register('./sw.js').then(async()=>{await navigator.serviceWorker.ready;$('offline-status').textContent='Works offline.';}).catch(()=>{});16}1718// Per-tool details, opened from the info button on each card.19const TOOLS={20 perspective:['Perspective',['JPEG and PNG.','Straightens verticals and horizontals from detected lines. Up to 4 MP and 2560 px.','Saved copies drop EXIF and color profiles.']],21 fuji:['Fuji',['RAF files, developed at half size with the camera\'s lens corrections.','16 film simulation looks as LUTs fitted from a Fuji body: close to the camera, not the camera\'s own rendering.','The in-camera JPEG can be saved as is.']],22 social:['Social',['JPEG, PNG and WebP.','Aspect ratios for photo and social, crop or pad, frame, vignette and grain.','Social ratios export with a 1080 short side. Photo ratios keep resolution up to 2160.']],23 ela:['ELA',['Error level analysis, as on FotoForensics. The picture is re-saved as JPEG at a chosen quality and the difference is amplified.','Regions edited or pasted at a different compression level stand out from the rest. Read it as a hint, not proof.','Native pixels up to 16 MP. The map saves as PNG.']]};24const toolSheet=$('tool-sheet');25for(const b of document.querySelectorAll('[data-info]'))b.onclick=e=>{e.preventDefault();const [title,paras]=TOOLS[b.dataset.info];$('tool-title').textContent=title;$('tool-text').replaceChildren(...paras.map(t=>{const p=document.createElement('p');p.textContent=t;return p;}));toolSheet.showModal();};26toolSheet.querySelector('[data-close]').onclick=()=>toolSheet.close();toolSheet.addEventListener('click',e=>{if(e.target===toolSheet)toolSheet.close();});