Obiekt Canvas to świetny wynalazek. Długo do niego nie podchodziłem, ze względu na początkową niekompatybilność wszystkich przeglądarek (zwłaszcza MSIE), poza tym nigdy nie był mi specjalnie potrzebny. Teraz jednak zaszła konieczność jego użycia, a najwięcej problemów sprawiło głupie 15 bajtów.
Jakiś czas temu musiałem zaimplementować prostą przycinarkę zdjęć, jaką posiada między innymi Facebook, Twitter czy Instagram. Do tego samego celu zresztą czyli do skadrowania zdjęcia profilowego przed wysłaniem go na serwer. Dzięki temu nie przesyła się całego zdjęcia (czasami jest to kilka MB), tylko wycięty fragment. Jest to szybsze i nie obciąża niepotrzebnie sieci.
Jak zwykle pierwszą myślą było napisanie go samemu, ale jako że nie bardzo wiedziałem, jak się do tego zabrać, postanowiłem najpierw skorzystać z gotowca. W razie czego potem się to zoptymalizuje.
Pogrzebałem trochę w internecie i wybrałem najmniejszy plugin, który co prawda nie grzeszy ilością funkcji i bajerów, ale też nie ich potrzebowałem. Stawiam przede wszystkim na minimalizm.
Cropit jest dosyć wiekowym pluginem i tylko kadruje, skaluje i obraca o 90° zdjęcie. Korzysta z obiektu Canvas, który jest już chyba standardem dla wszystkich przeglądarek. Poprawcie mnie, jeśli się mylę.
Jest to najmniejszy plugin, jaki znalazłem. Waży 38kB, po spakowaniu tylko 21kB i wykorzystuje bibliotekę jQuery. Jeśli jest coś mniejszego, to poproszę o linka.
Przejrzałem plik demonstracyjny i dosyć szybko ogarnąłem jego użycie. W skrócie sprowadza się do tego, żeby oprogramować odpowiednie zdarzenie pluginu, który po przycięciu zdjęcia przeniesie do ukrytego pola formularza odpowiednio wygenerowany plik JPG zakodowany w base64.
U mnie to wygląda tak:
// INICJALIZACJA PLUGINU
$('#Cropit').cropit({exportZoom:1, imageBackground:true, imageBackgroundBorderWidth:60});
// OBSŁUGA ZDARZEŃ
$('#Preview').mouseout(function() { CropItExport(); });
$('#Zoom').change(function() { CropItExport(); });
$('#RotateCw').click(function() { $('#Cropit').cropit('rotateCW'); CropItExport(); });
$('#RotateCcw').click(function() { $('#Cropit').cropit('rotateCCW'); CropItExport(); });
function CropItExport() { $('#Avatar').val($('#Cropit').cropit('export')); }
Samo wysłanie danych na serwer obsługuje się normalnie. A plik zapisuje się po zdekodowaniu zmiennej $_POST[„avatar”] i zapisanie jako pliku JPG.
Zawsze jakiś się pojawi. Tym razem przeglądarka usilnie odmawiała wyświetlenia przesłanego pliku. Sprawdziłem prawa dostępu, ścieżki i wszystko było OK. Odczytałem plik w różnych viewerach, nawet w Photoshopie, wszystko OK. Tylko najzwyklejsze IMG nie dawało rady.
Niemniej byłem przekonany, że problem tkwi w samym pliku JPG. Wykonałem więc próbę i zamiast zapisywać przesłany plik, od razu go wyświetliłem, a następnie zapisałem z poziomu przeglądarki. Porównałem oba pliki i...
Zapisany plik miał na początku 15 bajtów więcej!
Nie mam pojęcia, na którym etapie one się pojawiają i prawdę mówiąc nie chciało mi się tego sprawdzać. Jeśli ktoś z Was spotkał się z tym, proszę o informację. Zawsze się przyda :)
Banalnie proste. Jak już zdekodowałem przesłane dane do formy binarnej, po prostu usunąłem pierwsze 15 bajtów:
$bFile=substr($bFile,15,strlen($bFile));
Może to mało eleganckie, ale póki co działa. Być może kiedyś coś mnie najdzie i przepiszę całą bibliotekę zostawiając tylko najpotrzebniejsze rzeczy. I przy okazji znajdę błąd.
W końcu lubię wyważać otwarte drzwi i wymyślać koło na nowo :)