Utwórz projekt ↗
HTML / CSS / JS / LAB · KOD NA LICENCJI MIT

Kadrowanie obrazu w przeglądarce

Lokalny obraz, kwadratowy kadr i pobranie PNG.

Edytuj HTML, CSS i JS ↗ Otwórz konfigurator ↗

Gdzie wykorzystać ten przykład?

Narzędzia edycji, zegary i obsługa wskaźnika. Wariant „Kadrowanie obrazu w przeglądarce” możesz dopasować do kolorów i treści swojej strony.

Jak działa ten efekt?

Pointer Events, canvas i zegary przeglądarki pozwalają sterować elementami i przetwarzać pliki bez serwera.

Jak dodać go na stronę?

  1. Otwórz przykład w edytorze i podmień tekst oraz kolory.
  2. HTML wstaw w miejscu, w którym ma pojawić się element.
  3. CSS przenieś do arkusza stylów swojej strony. Reguły body z podglądu dopasuj do własnego układu.
  4. JavaScript uruchom po załadowaniu elementów HTML, na przykład przed zamknięciem </body>.
  5. Sprawdź działanie na telefonie, klawiaturą i z własną treścią.

Na co zwrócić uwagę?

Sprawdź dotyk i klawiaturę. Eksport plików oraz schowek mogą zależeć od możliwości i uprawnień przeglądarki.

Co możesz zmienić w konfiguratorze?

Nagłówek, Kolor akcentu, Zaokrąglenie. W edytorze kodu możesz dodatkowo zmienić całą strukturę i zachowanie przykładu.

Gotowy kod: Kadrowanie obrazu w przeglądarce

HTML

<section class="lab"><h2>Kadrowanie obrazu w przeglądarce</h2><label>Plik JPG, PNG lub WebP (do 10 MB)<input class="crop-file" type="file" accept="image/png,image/jpeg,image/webp"></label><label>Zoom <input class="crop-zoom" type="range" min="1" max="3" step=".05" value="1"></label><label>Pozycja X <input class="crop-x" type="range" min="0" max="100" value="50"></label><label>Pozycja Y <input class="crop-y" type="range" min="0" max="100" value="50"></label><canvas class="crop-canvas" width="360" height="360"></canvas><button class="crop-save" disabled>Pobierz kadr PNG</button><p class="crop-status" role="status">Obraz pozostaje na Twoim urządzeniu.</p><p class="lab-hint">Przetwarzanie lokalne. Wygenerowany PNG ma 360 × 360 px.</p></section>

CSS

*{box-sizing:border-box}body{margin:0;padding:35px 24px;background:#f4f5ef;color:#293322;font:15px/1.7 Arial,sans-serif;min-height:100vh;display:grid;place-items:center}button,input{font:inherit}button,a{touch-action:manipulation}button{cursor:pointer}button:focus-visible,a:focus-visible,summary:focus-visible{outline:3px solid #738858;outline-offset:4px}h2,h3,p{margin-top:0}[hidden]{display:none!important}@media(prefers-reduced-motion:reduce){*,*:before,*:after{animation:none!important;transition:none!important;scroll-behavior:auto!important}}
.lab{max-width:800px;margin:25px auto;padding:25px;border:1px solid #d4dec9;border-radius:14px;background:#fff;color:#273724;font:15px/1.6 system-ui,sans-serif;overflow-wrap:anywhere}.lab *{box-sizing:border-box}.lab h2{font-size:23px;margin:0 0 25px;line-height:1.3}.lab h3{line-height:1.3}.lab label{display:block;margin:10px 0}.lab input:not([type=checkbox]):not([type=radio]),.lab select,.lab textarea{font:inherit;padding:9px;border:1px solid #bac9ad;border-radius:6px;max-width:100%;background:#fff;color:#273724}.lab input[type=range]{width:100%;accent-color:#6f8e58}.lab input[type=color]{height:45px;width:70px}.lab input[type=checkbox]{accent-color:#6f8e58;margin-right:8px}.lab textarea{width:100%}.lab button{font:inherit;font-weight:600;border:0;border-radius:14px;background:#6f8e58;color:#fff;padding:10px 16px;cursor:pointer}.lab button:disabled{opacity:.45;cursor:default}.lab :focus-visible{outline:3px solid #315f8b;outline-offset:3px}.lab pre{white-space:pre-wrap;overflow-wrap:anywhere;background:#f0f4e9;padding:15px;font:12px/1.6 monospace}.lab table{border-collapse:collapse;width:100%}.lab th,.lab td{padding:10px;text-align:left;border-bottom:1px solid #d9e3ce}.lab progress{accent-color:#6f8e58}.lab .lab-hint{font-size:11px;color:#687861;border-top:1px solid #dbe3d0;padding-top:16px;margin-top:25px}.lab [hidden]{display:none!important}@media(max-width:480px){.lab{padding:16px;margin:10px auto}.lab h2{font-size:20px}.lab table{font-size:12px}.lab th,.lab td{padding:7px}}@media(prefers-reduced-motion:reduce){.lab *{animation:none!important;transition:none!important}}
.crop-canvas{display:block;width:min(100%,360px);height:auto;background:#e3ebd8;margin:15px auto}

JavaScript

const canvas=document.querySelector('.crop-canvas'),ctx=canvas.getContext('2d'),file=document.querySelector('.crop-file'),zoom=document.querySelector('.crop-zoom'),px=document.querySelector('.crop-x'),py=document.querySelector('.crop-y'),status=document.querySelector('.crop-status'),save=document.querySelector('.crop-save');let image;function draw(){if(!image||!ctx)return;const size=Math.min(image.naturalWidth,image.naturalHeight)/Number(zoom.value),x=(image.naturalWidth-size)*px.value/100,y=(image.naturalHeight-size)*py.value/100;ctx.clearRect(0,0,360,360);ctx.drawImage(image,x,y,size,size,0,0,360,360)}file.onchange=()=>{const f=file.files[0];if(!f)return;save.disabled=true;if(!['image/png','image/jpeg','image/webp'].includes(f.type)||f.size>10485760){status.textContent='Wybierz JPG, PNG lub WebP do 10 MB.';return}const url=URL.createObjectURL(f),img=new Image();img.onload=()=>{URL.revokeObjectURL(url);if(img.naturalWidth*img.naturalHeight>40000000){status.textContent='Obraz ma ponad 40 megapikseli.';return}image=img;zoom.value=1;draw();save.disabled=!ctx;status.textContent='Ustaw kadr i pobierz plik.'};img.onerror=()=>{URL.revokeObjectURL(url);status.textContent='Nie można odczytać obrazu.'};img.src=url};[zoom,px,py].forEach(i=>i.oninput=draw);save.onclick=()=>canvas.toBlob(blob=>{if(!blob)return;const url=URL.createObjectURL(blob),a=document.createElement('a');a.href=url;a.download='kadr.png';a.click();setTimeout(()=>URL.revokeObjectURL(url),1000)},'image/png');

Podobne przykłady