Notizen vom Team zu Handwerk, Formaten und den kleinen Entscheidungen hinter einem guten runden Zuschnitt.
Die Bibliothek cropperjs v2 und was sich gegenüber v1 geändert hat
Dieses Werkzeug basiert auf cropperjs Version 2.1.1, einer vollständigen Neuentwicklung der ursprünglichen cropperjs-Bibliothek. Die v2-Version ersetzt die alte konstruktorbasierte API (new Cropper(img, { aspectRatio: 1 })) durch eine Web-Components-Architektur. Der Zuschneide-Canvas, das Auswahl-Overlay und das Bildelement sind alles benutzerdefinierte HTML-Elemente, die über die CustomElementRegistry des Browsers registriert werden. Das bedeutet, dass das Shadow DOM alle internen Stile verwaltet: Es gibt keine separate cropper.css-Datei zu importieren, was eine Vite-Asset-Anfrage gegenüber v1 spart. Die Seitenverhältnis-Sperre wird jetzt direkt am Auswahlelement gesetzt (cropperSelection.aspectRatio = 1) und nicht mehr am Konstruktor, sodass das Verhältnis zur Laufzeit geändert werden kann, ohne die gesamte Zuschneideoberfläche neu zu initialisieren. Die Bibliothek wiegt 41.960 Byte roh und 12.175 Byte gzip, direkt aus dem Content-Length-Header von jsDelivr CDN gemessen. Diese 12 KB werden einmal pro Sitzung bezahlt und über alle voreingestellten Zuschneide-Routen via Vite-Chunk-Splitting wiederverwendet.
Wie die Ausgabe-Pixelmaße berechnet werden (kein Hochskalieren)
Wenn du die Zuschneideauswahl auf dem Bildschirm ziehst, liegen die Koordinaten, die du siehst, im Pixelraum des Quellbilds, nicht im CSS-Pixelraum. Dieser Unterschied ist auf hochauflösenden Bildschirmen wichtig: Ein Handy mit einem Device-Pixel-Ratio von 3 zeigt ein 300 CSS-Pixel breites Bild als 900 echte Pixel an, aber die Auswahlkoordinaten beziehen sich auf die 900 echten Pixel, nicht auf die 300 CSS-Pixel. Die heruntergeladene Ausgabedatei enthält genau die Anzahl Pixel, die das Auswahlrechteck im Quellbild repräsentiert. Der Zuschneidevorgang ruft selection.$toCanvas() aus der cropperjs-v2-API auf, eine asynchrone Methode, die ein frisches HTMLCanvasElement in den Pixelmaßen der Auswahl zurückgibt. Dieser Canvas wird dann an canvas.toBlob() für PNG, JPG oder WebP übergeben oder an den @jsquash/avif-Encoder für AVIF. Es wird kein Hochskalierungsschritt eingefügt. Ist deine Auswahl 800 Pixel breit, ist die Ausgabe 800 Pixel breit. Social-Media-Vorlagen (1080x1080 für Instagram, 1280x720 für YouTube) liefern diese Größen nur dann, wenn das Quellbild genug Pixel enthält, um die Auswahl zu füllen.
Entfernen von EXIF-Metadaten und was dabei verloren geht
Jeder Export entfernt EXIF-, IPTC-, XMP- und ICC-Profildaten. Das geschieht auf Canvas-Ebene: Der Browser zeichnet die dekodierten Bildpixel auf ein HTMLCanvasElement und der Canvas kodiert eine neue Datei. Der Canvas kennt keine Metadaten-Container, er speichert nur Pixelwerte und Kodierparameter. Entfernt werden GPS-Koordinaten, Kameramarke und -modell, Brennweite des Objektivs, Belichtungseinstellungen, Copyright-Felder und Farbprofil-Tags. Das sRGB-Farbprofil ist faktisch die Annahme, die der Canvas trifft: Farben werden über die Display-Pipeline des Browsers gerendert und ohne angehängtes Profil neu kodiert. Für die meisten Web-Publishing- und Social-Media-Anwendungen ist das Entfernen von EXIF erwünscht, da GPS-Daten Ortsinformationen offenlegen können, die der Nutzer nicht teilen wollte. Für professionelle Foto-Workflows, in denen Farbprofil-Genauigkeit wichtig ist, gilt: Die ICC-Profiltreue wird nicht erhalten und für die Auslieferung an Druck oder Publikation sollte ein farbverwaltetes Export-Werkzeug verwendet werden.
Was beim Zuschneiden eines animierten GIF passiert
Wenn du ein animiertes GIF auf das Zuschneidewerkzeug ziehst, dekodiert der Browser nur das erste Bild in das Bildelement, das vom Zuschneide-Canvas verwendet wird. Das ist ein Browser-Verhalten, keine Einschränkung von cropperjs: Das HTMLImageElement legt einzelne Frames eines animierten GIF nicht so für JavaScript offen, dass die Canvas-API darüber iterieren könnte. Das Ergebnis ist, dass nur das erste Bild für die Zuschneideauswahl verfügbar ist und die endgültige Ausgabe ein Standbild in dem von dir gewählten Format ist. Ist die Eingabe ein GIF und wählst du GIF als Ausgabe, enthält die canvas.toBlob-Implementierung des Browsers keinen GIF-Encoder, sodass die Ausgabe still auf PNG zurückfällt. Das Werkzeug lehnt GIF als Ausgabeformat-Option ausdrücklich ab, um diesen stillen Downgrade zu vermeiden. Möchtest du alle Frames einer Animation zuschneiden, brauchst du ein Werkzeug, das Frame für Frame arbeitet, was dieses Werkzeug nicht unterstützt.
Tastaturnavigation und Barrierefreiheit
Das Auswahlelement von cropperjs v2 implementiert die Tastaturnavigation als Teil seiner Web-Component-Spezifikation. Sobald du mit Tab zur Zuschneideauswahl gelangst, bewegen die Pfeiltasten den Rahmen pixelweise in die gedrückte Richtung. Umschalt plus Pfeiltaste verschiebt den Rahmen um zehn Pixel. Das ist nativ zugänglich, ohne Workaround für Screenreader oder benutzerdefiniertes JavaScript-Overlay: Der Tastatur-Handler lebt im Shadow Root des Auswahlelements und reagiert auf Keydown. Das ist wichtig für Nutzer, die auf reine Tastaturnavigation angewiesen sind, einschliesslich bestimmter Assistenz-Setups, motorischer Barrierefreiheits-Geräte und Präzisions-Workflows, in denen ein Trackpad keine zuverlässige sub-pixelgenaue Ausrichtung erreichen kann. Die an die Auswahl angehängte Live-Pixelanzeige aktualisiert sich ebenfalls bei jedem Tastendruck, sodass Screenreader-Nutzer mit aria-live-Regionen auf der Anzeige die aktuellen Maße hören können. Tastatur-Barrierefreiheit ist ein Bereich, in dem dieses Werkzeug iLoveIMG und img2go voraus ist, die keine Pfeiltasten-Navigation beim Zuschneiden implementieren.
Format-Kompromisse nach dem Zuschneiden
Die Format-Auswahl im Fertig-Bildschirm bietet vier Optionen. PNG ist verlustfrei: Jedes Pixel im Zuschneidebereich wird genau so gespeichert, wie es aus der Quelle dekodiert wurde. Die Dateigröße ist bei gleichem Inhalt größer als JPG, typischerweise drei- bis fünfmal größer für ein Foto. JPG verwendet verlustbehaftete Kompression bei Qualität 0,9 (auf einer Skala von 0 bis 1), was in etwa der Voreinstellung Hohe Qualität in den meisten Desktop-Editoren entspricht. Bei q0,9 ist der Unterschied zwischen Original und Ausgabe auf einem Standardmonitor in der Regel nicht sichtbar, die Datei ist aber deutlich kleiner. WebP erzeugt bei derselben Qualitätseinstellung eine Datei, die in unseren Kodiertests rund 25 bis 35 Prozent kleiner ist als JPG, bei gleicher Wahrnehmungsqualität auf Fotos. WebP unterstützt zudem einen verlustfreien Modus und erhält Transparenz. AVIF mit Qualität 0,9 über die Bibliothek @jsquash/avif erzeugt die kleinste Ausgabe der vier Formate, aber der erste Kodiervorgang in einer Sitzung erfordert das Herunterladen eines 870 KB grossen WASM-Moduls. Folgende AVIF-Kodierungen im selben Tab sind schnell, weil das Modul bereits geladen ist.