EOS PHOTO — Éditeur photo
STUDIO LUMEN
ÉDITION LOCALE · NOUVEAU PROJET
Toile vide
ZOOM 100%
Votre toile attend une imageImportez un PNG ou JPG, ou déposez-le ici
`).reverse().join('');document.querySelectorAll('.layer').forEach(e=>e.onclick=()=>{active=+e.dataset.i;setup()});document.querySelectorAll('.eye').forEach(e=>e.onclick=ev=>{ev.stopPropagation();let i=+e.parentElement.dataset.i;save();layers[i].visible=!layers[i].visible;setup();render()})} function render(){vctx.clearRect(0,0,W,H);vctx.fillStyle='#fff';vctx.fillRect(0,0,W,H);layers.forEach(l=>{if(l.visible)vctx.drawImage(l.c,0,0)});let z=$('#zoom').value/100;view.style.width=W*z+'px';view.style.height=H*z+'px';$('#zoomVal').textContent=$('#zoom').value+'%'} function pos(e){let r=view.getBoundingClientRect();return{x:(e.clientX-r.left)*W/r.width,y:(e.clientY-r.top)*H/r.height}} function current(){if(active<0)newLayer();return layers[active].c.getContext('2d')} function applyAdjust(){if(active<0)return;save();let l=layers[active],tmp=document.createElement('canvas');tmp.width=W;tmp.height=H;let c=tmp.getContext('2d');let b=+$('#brightness').value,co=+$('#contrast').value,s=+$('#saturation').value,f=$('#filter').value;c.filter=`brightness(${1+b/100}) contrast(${1+co/100}) saturate(${1+s/100}) ${f==='none'?'':f}`;c.drawImage(l.c,0,0);l.c=tmp;render()} function transform(type){if(active<0)return;save();let l=layers[active],tmp=document.createElement('canvas');if(type==='rot') {tmp.width=H;tmp.height=W}else{tmp.width=W;tmp.height=H}let c=tmp.getContext('2d');c.translate(tmp.width/2,tmp.height/2);if(type==='left'||type==='right')c.rotate((type==='left'?-90:90)*Math.PI/180);if(type==='flip')c.scale(-1,1);c.drawImage(l.c,-W/2,-H/2);l.c=tmp;if(type==='rot'){[W,H]=[H,W]}setup();render()} view.onpointerdown=e=>{if(!layers.length)newLayer('Arrière-plan');let p=pos(e);start=p;drawing=true;view.setPointerCapture(e.pointerId);let c=current();if(tool==='brush'||tool==='eraser'){save();c.globalCompositeOperation=tool==='eraser'?'destination-out':'source-over';c.strokeStyle=$('#color').value;c.globalAlpha=$('#opacity').value/100;c.lineWidth=$('#size').value;c.lineCap='round';c.beginPath();c.moveTo(p.x,p.y);c.lineTo(p.x+.1,p.y+.1);c.stroke()}else if(tool==='eyedrop'){let d=vctx.getImageData(p.x,p.y,1,1).data;$('#color').value='#'+[d[0],d[1],d[2]].map(x=>x.toString(16).padStart(2,'0')).join('');drawing=false}else if(tool==='text'){let t=prompt('Texte à ajouter');if(t){save();c.globalAlpha=1;c.fillStyle=$('#color').value;c.font='bold 42px Syne, sans-serif';c.fillText(t,p.x,p.y)}drawing=false;render() }else if(tool==='rect'){save();}} view.onpointermove=e=>{if(!drawing)return;let p=pos(e),c=current();if(tool==='brush'||tool==='eraser'){c.lineTo(p.x,p.y);c.stroke()}else if(tool==='rect'){render();vctx.save();vctx.strokeStyle=$('#color').value;vctx.lineWidth=$('#size').value/3;vctx.strokeRect(start.x,start.y,p.x-start.x,p.y-start.y);vctx.restore()}render()};view.onpointerup=e=>{if(!drawing)return;drawing=false;let p=pos(e),c=current();if(tool==='rect'){c.strokeStyle=$('#color').value;c.lineWidth=$('#size').value/3;c.globalAlpha=$('#opacity').value/100;c.strokeRect(start.x,start.y,p.x-start.x,p.y-start.y)}c.globalCompositeOperation='source-over';c.globalAlpha=1;render()}; $('#file').onchange=e=>{let f=e.target.files[0];if(f)loadFile(f)};function loadFile(f){let im=new Image;im.onload=()=>{save();W=im.naturalWidth;H=im.naturalHeight;layers=[];newLayer(f.name.replace(/\.[^.]+$/,''));layers[0].c.getContext('2d').drawImage(im,0,0);setup();render();$('#docStatus').textContent='MODIFIÉ · '+f.name};im.src=URL.createObjectURL(f)} $('#dropzone').ondragover=e=>{e.preventDefault();$('#dropzone').classList.add('drop')};$('#dropzone').ondragleave=()=>$('#dropzone').classList.remove('drop');$('#dropzone').ondrop=e=>{e.preventDefault();$('#dropzone').classList.remove('drop');let f=e.dataTransfer.files[0];if(f&&f.type.startsWith('image/'))loadFile(f)}; document.querySelectorAll('[data-tool]').forEach(b=>b.onclick=()=>{tool=b.dataset.tool;document.querySelectorAll('[data-tool]').forEach(x=>x.classList.toggle('active',x===b))});$('#addLayer').onclick=()=>{save();newLayer()};$('#delLayer').onclick=()=>{if(active>=0){save();layers.splice(active,1);active=Math.min(active,layers.length-1);setup();render()}};$('#apply').onclick=applyAdjust;$('#rotL').onclick=()=>transform('left');$('#rotR').onclick=()=>transform('right');$('#flip').onclick=()=>transform('flip');$('#resetAdjust').onclick=()=>{['brightness','contrast','saturation'].forEach(x=>$('#'+x).value=0);['brightOut','contrastOut','satOut'].forEach(x=>$('#'+x).textContent='0')};$('#resize').onclick=()=>{let nw=+$('#resizeW').value;if(active<0||!nw)return;save();let nh=Math.round(H*nw/W);let t=document.createElement('canvas');t.width=nw;t.height=nh;t.getContext('2d').drawImage(layers[active].c,0,0,nw,nh);layers[active].c=t;W=nw;H=nh;setup();render()};$('#zoom').oninput=render; $('#undo').onclick=()=>{if(undoStack.length){redoStack.push(state());restore(undoStack.pop())}};$('#redo').onclick=()=>{if(redoStack.length){undoStack.push(state());restore(redoStack.pop())}};$('#new').onclick=()=>{if(confirm('Commencer un nouveau projet ?')){W=900;H=600;layers=[];active=-1;setup();render()}};$('#download').onclick=()=>{let a=document.createElement('a');a.download='studio-lumen.png';a.href=view.toDataURL('image/png');a.click()}; ['size','opacity'].forEach(x=>$('#'+x).oninput=()=>$('#'+x+'Out').textContent=$('#'+x).value+(x==='size'?' px':'%'));[['brightness','brightOut'],['contrast','contrastOut'],['saturation','satOut']].forEach(([a,b])=>$('#'+a).oninput=()=>$('#'+b).textContent=$('#'+a).value); $('#unlock').onclick=()=>{if($('#pass').value==='LUMEN'){sessionStorage.setItem('lumen-ok','1');$('#lock').remove()}else $('#err').textContent='Mot de passe incorrect'};$('#pass').onkeydown=e=>{if(e.key==='Enter')$('#unlock').click()};if(sessionStorage.getItem('lumen-ok')==='1')$('#lock').remove();$('#mobilePanel').onclick=()=>$('#panel').classList.toggle('open');setup();render();