- commit
- cfc3fd2e51a7e27b5b5016512d369afddcab42af
- parent
- 175cac3adadb9beff9160feac2a6988b865667c0
- author
- Dami <dami.etoile@gmail.com>
| M | app.mjs | 11 | +++++++++-- |
| M | fuji.mjs | 12 | ++++++++++-- |
| M | style.css | 6 | +++--- |
@@ -29,10 +29,17 @@ function syncControls(){
2929 function setBusy(value) {busy=value;$('busy').hidden=!value;syncControls();}3030 function currentParams(){const s=Number($('strength').value)/100;return [Number($('rotation').value),base[1]*s,base[2]*s,base[3]*s];}3131 function updateLabels(){const r=Number($('rotation').value);$('rotation-value').value=`${r>0?'+':''}${r.toFixed(2)}°`;$('strength-value').value=`${$('strength').value}%`;}32+// Size the canvas box to the picture inside the stage, so the overlay covers exactly the picture.33+function layout(){34+ if(!canvas.width)return;35+ const cs=getComputedStyle(stage),w=stage.clientWidth-parseFloat(cs.paddingLeft)-parseFloat(cs.paddingRight),h=stage.clientHeight-parseFloat(cs.paddingTop)-parseFloat(cs.paddingBottom);36+ const s=Math.min(w/canvas.width,h/canvas.height),cw=Math.max(1,Math.floor(canvas.width*s)),ch=Math.max(1,Math.floor(canvas.height*s));37+ canvas.style.width=overlay.style.width=cw+'px';canvas.style.height=overlay.style.height=ch+'px';38+}3239 function draw(){3340 const before=showBefore||holdBefore,source=before||!rendered?original:rendered;3441 if(!source)return;35- canvas.width=source.width;canvas.height=source.height;ctx.drawImage(source,0,0);42+ canvas.width=source.width;canvas.height=source.height;ctx.drawImage(source,0,0);layout();3643 $('compare').setAttribute('aria-pressed',String(before&&Boolean(rendered)));3744 drawOverlay();3845 }@@ -106,6 +113,7 @@ $('reset').onclick=()=>{clearTimeout(renderTimer);renderId++;resetValues();cropM
106113 107114 // Press and hold the photo to peek at the original.108115 const stage=$('stage');116+new ResizeObserver(()=>{layout();drawOverlay();}).observe(stage);109117 stage.addEventListener('pointerdown',e=>{if(!rendered||busy||e.target.closest('button'))return;holdBefore=true;draw();});110118 for(const type of ['pointerup','pointercancel','pointerleave'])stage.addEventListener(type,()=>{if(!holdBefore)return;holdBefore=false;draw();});111119 stage.addEventListener('contextmenu',e=>e.preventDefault());@@ -152,7 +160,6 @@ async function save(format){
152160 status(`Saved ${c.width} x ${c.height}`);153161 }catch(e){status(e.message,true);}finally{setBusy(false);}154162 }155-new ResizeObserver(drawOverlay).observe(canvas);156163 if('serviceWorker'in navigator){navigator.serviceWorker.register('./sw.js').catch(()=>{});let hadController=Boolean(navigator.serviceWorker.controller);navigator.serviceWorker.addEventListener('controllerchange',()=>{if(hadController&&!original)location.reload();hadController=true;});}157164 syncCrop();158165 try{await rpc('init');}catch(e){status(e.message,true);}finally{setBusy(false);}@@ -23,7 +23,15 @@ const NEUTRAL_URLS={100:new URL('./assets/luts/neutral-dr100.png',import.meta.ur
2323 const FROM_CAMERA={'Provia':'provia','Velvia':'velvia','Astia':'astia','Classic Chrome':'classic_chrome','Pro Neg. Hi':'pro_neg_high','Pro Neg. Std':'pro_neg_std','Eterna':'eterna',2424 'Acros':'acros','Acros+R':'acros-red','Acros+Ye':'acros-yellow','Acros+G':'acros-green','Monochrome':'mono','Monochrome+R':'mono-red','Monochrome+Ye':'mono-yellow','Monochrome+G':'mono-green','Sepia':'sepia'};2525 26-const tool=$('tool'),canvas=$('canvas'),ctx=canvas.getContext('2d'),photo=$('photo');26+const tool=$('tool'),canvas=$('canvas'),ctx=canvas.getContext('2d'),photo=$('photo'),stageEl=$('stage');27+// Size the picture box to fit the stage, same for the developed canvas and the camera JPEG.28+function layout(){29+ const cs=getComputedStyle(stageEl),w=stageEl.clientWidth-parseFloat(cs.paddingLeft)-parseFloat(cs.paddingRight),h=stageEl.clientHeight-parseFloat(cs.paddingTop)-parseFloat(cs.paddingBottom);30+ for(const [el,iw,ih] of [[canvas,canvas.width,canvas.height],[photo,photo.naturalWidth,photo.naturalHeight]]){31+ if(!iw||!ih)continue;const s=Math.min(w/iw,h/ih);el.style.width=Math.max(1,Math.floor(iw*s))+'px';el.style.height=Math.max(1,Math.floor(ih*s))+'px';32+ }33+}34+new ResizeObserver(layout).observe(stageEl);photo.addEventListener('load',layout);2735 let current=null,busy=false,toastTimer,sim='provia',dr=100,showCamera=false,holdCamera=false,renderId=0,cameraUrl=null;2836 const loaded=new Set(),loading=new Map();2937 @@ -54,7 +62,7 @@ async function render(){
5462 await Promise.all([ensureLut('neutral',dr,NEUTRAL_URLS[dr]||NEUTRAL_URLS[100]),ensureLut('sim',sim,LUT_URLS[sim])]);5563 const r=await rpc('render',{dr:NEUTRAL_URLS[dr]?dr:100,sim});5664 if(id!==renderId)return;57- canvas.width=r.w;canvas.height=r.h;ctx.putImageData(new ImageData(r.data,r.w,r.h),0,0);65+ canvas.width=r.w;canvas.height=r.h;ctx.putImageData(new ImageData(r.data,r.w,r.h),0,0);layout();5866 }catch(e){status(e.message,true);}5967 }6068 async function openFile(file){@@ -121,8 +121,8 @@ h1, h2, h3, p { margin: 0; }
121121 -webkit-touch-callout: none; user-select: none; -webkit-user-select: none;122122 touch-action: none;123123 }124-.canvas-wrap { position: relative; max-width: 100%; max-height: 100%; display: flex; }125-#canvas { display: block; max-width: 100%; max-height: 100%; width: auto; height: auto; object-fit: contain; }124+.canvas-wrap { position: relative; }125+#canvas { display: block; }126126 #overlay { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; }127127 .tool[data-state="empty"] .canvas-wrap { display: none; }128128 @@ -234,7 +234,7 @@ input[type=range]::-moz-range-thumb { width: 26px; height: 26px; border: 0; bord
234234 235235 /* ---------- Fuji ---------- */236236 237-#photo { display: block; max-width: 100%; max-height: 100%; width: auto; height: auto; object-fit: contain; }237+#photo { display: block; }238238 .chips { display: flex; gap: 8px; overflow-x: auto; scrollbar-width: none; padding: 4px 16px; margin: 0 -16px; -webkit-overflow-scrolling: touch; scroll-snap-type: x proximity; }239239 .chips::-webkit-scrollbar { display: none; }240240 .chip-btn { flex: none; height: 36px; padding: 0 14px; border-radius: 18px; background: var(--surface-2); font-size: 14px; font-weight: 500; color: var(--label); white-space: nowrap; scroll-snap-align: center; }