Notatki zespołu o rzemiośle, formatach i drobnych decyzjach stojących za dobrym okrągłym przycięciem.
Biblioteka cropperjs v2 i zmiany względem wersji 1
Narzędzie działa na cropperjs w wersji 2.1.1, całkowicie napisanej od nowa względem oryginalnej biblioteki cropperjs. Wersja 2 zastępuje stary konstruktor (new Cropper(img, { aspectRatio: 1 })) architekturą Web Components. Płótno kadru, nakładka zaznaczenia i element obrazu to niestandardowe elementy HTML zarejestrowane przez przeglądarkowy CustomElementRegistry. Oznacza to, że Shadow DOM obsługuje wszystkie wewnętrzne style: nie ma osobnego pliku cropper.css do zaimportowania, co eliminuje jedno żądanie zasobu Vite względem v1. Blokada proporcji jest teraz ustawiana bezpośrednio na elemencie zaznaczenia (cropperSelection.aspectRatio = 1), a nie w konstruktorze, więc proporcje można zmieniać w czasie działania bez ponownej inicjalizacji całego interfejsu kadrowania. Biblioteka waży 41 960 bajtów surowych i 12 175 bajtów po kompresji gzip, zmierzone bezpośrednio z nagłówka content-length CDN jsDelivr. Te 12 KB płaci się raz na sesję i jest ponownie wykorzystywane na wszystkich stronach presetów kadrowania dzięki podziałowi chunków Vite.
Jak obliczane są wymiary wyjściowe w pikselach (bez skalowania w górę)
Gdy przeciągasz zaznaczenie kadru na ekranie, współrzędne, które widzisz, są w przestrzeni pikseli źródła, a nie w przestrzeni pikseli CSS. To rozróżnienie ma znaczenie na ekranach o wysokiej gęstości pikseli: telefon o stosunku 3× pokazuje obraz szeroki na 300 pikseli CSS jako 900 pikseli rzeczywistych, ale współrzędne zaznaczenia odzwierciedlają te 900 pikseli rzeczywistych, nie 300 CSS. Plik wyjściowy, który pobierasz, zawiera dokładnie tyle pikseli, ile prostokąt zaznaczenia reprezentuje w obrazie źródłowym. Operacja kadrowania wywołuje selection.$toCanvas() z API cropperjs v2, asynchroniczną metodę zwracającą świeży HTMLCanvasElement w wymiarach pikseli zaznaczenia. To płótno jest następnie przekazywane do canvas.toBlob() dla PNG, JPG lub WebP, albo do enkodera @jsquash/avif dla AVIF. Nie ma żadnego kroku skalowania w górę. Jeśli zaznaczenie ma 800 pikseli szerokości, wyjście też ma 800 pikseli szerokości. Presety platform społecznościowych (1080×1080 dla Instagram, 1280×720 dla YouTube) są dostarczane w tych wymiarach tylko wtedy, gdy obraz źródłowy zawiera wystarczająco dużo pikseli, by wypełnić zaznaczenie.
Usuwanie metadanych EXIF i co zostaje utracone
Każdy eksport usuwa dane EXIF, IPTC, XMP oraz profile ICC. Dzieje się to na poziomie potoku płótna: przeglądarka rysuje zdekodowane piksele obrazu na HTMLCanvasElement, a płótno koduje do nowego pliku. Płótno nie ma pojęcia o kontenerach metadanych, przechowuje tylko wartości pikseli i parametry kodowania. To, co zostaje usunięte, obejmuje współrzędne GPS, markę i model aparatu, ogniskową obiektywu, ustawienia ekspozycji, pola praw autorskich i tagi profilu kolorów. Profil kolorów sRGB jest zakładany domyślnie: kolory są renderowane przez potok wyświetlania przeglądarki i kodowane ponownie bez dołączonego profilu. Dla większości publikacji w internecie i mediach społecznościowych usunięcie EXIF jest preferowane, ponieważ dane GPS mogą ujawnić informację o lokalizacji, której użytkownik nie zamierzał udostępniać. Dla profesjonalnych przepływów fotograficznych, gdzie liczy się dokładność profilu kolorów, warto pamiętać, że wierność profilu ICC nie jest zachowana, a do dostarczania materiałów do druku lub publikacji należy użyć narzędzia z zarządzaniem kolorem.
Co dzieje się przy kadrowaniu animowanego GIF
Gdy upuścisz animowany GIF do narzędzia kadrowania, przeglądarka dekoduje tylko pierwszą klatkę do elementu obrazu używanego przez płótno kadru. To zachowanie przeglądarki, nie ograniczenie cropperjs: HTMLImageElement nie udostępnia poszczególnych klatek animowanego GIF do JavaScript w sposób, w jaki API płótna mogłoby je iterować. Wynik jest taki, że tylko pierwsza klatka jest dostępna do zaznaczenia kadru, a końcowe wyjście to nieruchomy obraz w wybranym formacie. Jeśli wejście to GIF i wybierzesz GIF jako wyjście, implementacja canvas.toBlob w przeglądarce nie zawiera enkodera GIF, więc wyjście po cichu spada do PNG. Narzędzie wprost odrzuca GIF jako opcję formatu wyjściowego, by uniknąć tego cichego obniżenia. Jeśli musisz przyciąć wszystkie klatki animacji, potrzebujesz narzędzia działającego klatka po klatce, czego to narzędzie nie obsługuje.
Nawigacja klawiaturą i dostępność
Element zaznaczenia cropperjs v2 implementuje nawigację klawiaturą jako część specyfikacji swojego Web Component. Gdy przejdziesz Tabem do zaznaczenia kadru, strzałki przesuwają ramkę o jeden piksel w kierunku naciśniętym. Shift plus strzałka przesuwa ramkę o dziesięć pikseli. Jest to natywnie dostępne bez obejścia dla czytnika ekranu czy własnej nakładki JavaScript: obsługa klawiatury żyje wewnątrz shadow root elementu zaznaczenia i wyzwala się przy zdarzeniu keydown. Ma to znaczenie dla użytkowników polegających wyłącznie na klawiaturze, w tym niektórych konfiguracji technologii asystujących, urządzeń motorycznej dostępności i precyzyjnych przepływów, gdzie gładzik nie osiąga niezawodnie subpikselowej dokładności. Podgląd pikseli na żywo dołączony do zaznaczenia również aktualizuje się przy każdym naciśnięciu, więc użytkownicy czytników ekranu z regionami aria-live na podglądzie słyszą zmianę bieżących wymiarów. Dostępność klawiaturowa to obszar, w którym to narzędzie wyprzedza iLoveIMG i img2go, które nie implementują nawigacji strzałkami w kadrowaniu.
Wybór formatu po kadrowaniu, kompromisy
Selektor formatu na ekranie końcowym daje cztery opcje. PNG jest bezstratny: każdy piksel w obszarze kadru jest zapisany dokładnie tak, jak został zdekodowany ze źródła. Rozmiar pliku jest większy niż JPG dla tej samej zawartości, zwykle od trzech do pięciu razy większy dla zdjęcia. JPG stosuje kompresję stratną na jakości 0,9 (w skali od 0 do 1), co odpowiada mniej więcej presetowi wysokiej jakości w większości edytorów desktopowych. Przy q0,9 różnica między oryginałem a wyjściem zwykle nie jest widoczna na standardowym monitorze, ale plik jest znacząco mniejszy. WebP przy tym samym ustawieniu jakości daje plik o około 25 do 35 procent mniejszy niż JPG w naszych testach kodowania, przy tej samej jakości percepcyjnej dla zdjęć. WebP obsługuje też tryb bezstratny i zachowuje przezroczystość. AVIF na jakości 0,9 przez bibliotekę @jsquash/avif daje najmniejsze wyjście z czterech formatów, ale pierwsze kodowanie w sesji wymaga pobrania modułu WASM o rozmiarze 870 KB. Kolejne kodowania AVIF w tej samej zakładce są szybkie, bo moduł jest już załadowany.