Mire kettőt pislogsz már kijött négy Chrome verzió és egy új Firefox is sunyiban. Eszméletlen tempóban gyarapodnak a lehetőségek, miket is tudsz csinálni egy weboldalon keresztül. A hétvégén a HTML5 kis barátai közül négy API-t próbáltam ki, a Canvast, a WebWorkereket, a File API-t és a Drag and Drop eventeket egy nagyon egyszerű kis projekten keresztül: feltöltesz egy képet, a böngésző pedig egy nagyon egyszerű szűrővel feldolgozza. Gyakorlatilag olyan, mint az Instagram, csak böngészőben fut, a retró képszűrőt meg annyi, hogy úgy néz ki minden kép, mintha egy huszonöt éves Macintoshon néznéd. Szóval valójában egyáltalán nem olyan.

Eddig a show része. Ha érdekel a tell is, a hajtás után kicsit körbetáncoljuk, hogy is készült.
Ja, a kódrészletekben CoffeeScriptet használok, ne ijedj meg, ha nem ismered még: ez olyan, mintha pszeudokódban írnál, ami aztán lefordul igazi JavaScriptre. A function(){} helyett elég a ->, a this helyett a @, ahol csak lehet, el tudod hagyni a zárójelet, satöbbi. Van még egy csomó remek egyszerűsítés, amivel lényegesen könnyebben tudsz JS-t írni, érdemes kipróbálni.
Atkinson dithering
Régen örültünk, ha a monitor (meg a nyomtató) képes volt megjelníteni a fekete mellett a fehéret is But you know, we were happy in those days, though we were poor. / Because we were poor. Az ennél színesebb képeket, hogy meg tudjuk jeleníteni, le kellett valahogy butítani. Erre sokféle algoritmus volt, de a legszebb eredményt szerintem az Atkinson dithering adta, és ezt most nem is fanboyságból mondom — Bill Atkinson annó az ősmacintosh csapat tagja volt.
Az Aktinson dithering végigmegy minden pixelen, leviszi feketére vagy fehérre, a pixelértékbeli maradékot pedig elosztja a szomszédos pixelek között. Azaz:
Plusz, mivel a bejövő kép minden valószínűség szerint színes lesz, le kell kevernünk szürkeárnyalatosba:
Canvas
(elérhető Safari, Chrome, Firefox 3 fölött, Opera 10 fölött, IE 7 fölött, meg a webkites mobilböngészőkön. Szóval gyakorlatilag mindenhol.)
A Canvas egy remek eszköz elméletben arra, hogy olyan képmanipulációkat csinálj, amikre alapból képtelen lennél a böngészővel. Kőprimitív, pár segédfunkción (pont-pont-vesszőcske) kívül magadra vagy hagyja: nesze itt vannak a pixelek, oldd meg. Nekünk mondjuk pont ez kell, szóval hajrá. Képet betölteni canvasra így lehet:
A fenti kódban a ctx a kétdimenziós kontextus. Ha jól értem, a WebGL használja a 3d-s kontextusát a Canvasnak, de ezzel még nem volt dolgom. Constructorral létrehozunk egy új kép elemet, megadjuk a forrását és rácsatolunk egy eseménykezelőt, hogy mihelyst betöltötte, tegye ki a kép tartalmát a canvasra (drawImage [kép elem], [x], [y]), majd kérje is vissza azonnal a pixelértékeket (getImageData [startX, [startY], [endX], [endY]). Itt viszont álljunk meg egy szóra.
origin-clean
A canvas nagyon szigorú kóserszabályokat tart. Ha bármi tisztátalan dolgot csinálsz, azzal a canvas is tisztátalanná válik, tisztátalan canvashez meg gyakorlatilag nem érhetsz hozzá, a pixeladatokat meg pláne nem kérheted le. Ezért kapsz SECURITY_ERR exceptiont ha file:///-ből akarsz képet betölteni, még akkor is, ha a böngészőlap is ott van mellette, ugyanabban a mappában. Emlékszel még az XMLHttpRequest same-origin korlátozására? Ez olyan, csak lényegesen bosszantóbb. Szóval uccu, nyiss meg egy statikus szervert, csak azért, hogy továbbléphess.
WebWorker
(elérhető Firefox 3.5, Safari 4, Chrome 10, Opera 10.6 és későbbi verziókban. Szóval még nem nagyon)
Ha a képfeldolgozó funkciókat kiszervezzük egy Workerbe, a feldolgozástól nem fog beakadni a weblap, pláne a böngésző; közben lehet mást is csinálni. A WebWorker lehetőséget ad arra, hogy háttérben futó threadeket hozzunk létre, amik igaz csak egy kis résen keresztül tudnak kommunikálni az anyascripttel, de cserébe háborítatlanul tudnak dolgozni, anélkül, hogy felpattanna a ‘script not responding, vesd a földle, dulván’ ablak.
Egy script bárhány workert tud létrehozni (worker is tud workert csinálni (házi feladat forkbombot írni!)), egymással eseménykezelőkön keresztül kommunikálnak. Valahogy így:
A Worker és anyja kölcsönösen feliratkoznak a másik message eseményére, majd postMessage-en keresztül tudnak adatot küldeni egymásnak, a feldolgozott képet vagy akár azt, hogy hol tartanak, hogy aztán abból szép <progress> csíkot tudj csinálni. A fenti kódra a worker így válaszol:
A this/@ a CoffeeScript bábáskodása miatt kell, ugyanis alapból minden lefordított kódot saját closure-ba pakol, hogy véletlenül se lógjon ki semmi a globális scope-ba. Egyébként WebWorker kontextusban a self is a globális scope-ra vonatkozik, de így… szebb.
Drag and Drop
Internet Explorerben az 5.0(!!) óta elérhető a drag and drop, ez lett szépen beemelve a HTML5-be, miután a Safari, majd a Firefox is implementálta. Sajnos nem a leg…egyszerűbb és kényelmesebb dolog a világon, PPK például lazán kijelentette, hogy annyira katasztrófa az egész, hogy soha, semmilyen körülmények között nem szabad használni, mégis, mivel ezen keresztül jobban tudunk a böngészőn túli világgal kommunikálni, ki kellett próbálnom.
Az egyszerűség kedvéért a HTML-ünk összesen ennyi:
<img src="default.png" id="imagewell">
Ahhoz, hogy ez az <img> tudjon fogadni ráhúzott dolgokat, először kapásból ki kell lőnünk az alapviselkedést, ami ezt megakadályozza (értitek, dupla tagadás):
És ha már ottvagyunk, jelezzük valahogy, hogy itt biza elfogadjuk a ráhúzott dolgokat, csillogtatva GIMP skilljeimet:
Ha feliratkozol a drop eseményre, megkapsz mindent, amit rádhúznak, abból aztán neked kell kimazsolázni azt, ami számodra hasznosítható. Egyelőre nézzük meg mi történik ha egy fájlt húzunk be:
FileReader
(Firefox 3.6 vagy Chrome 10. Még a Safari se viszi tisztességesen, nem hogy az IE.)
A FileReader segítségével be tudunk… olvasni egy… fájlt. Ha akarjuk, szövegként (readAsText), ha akarjuk, blobként (readAsBinaryString, readArrayBuffer), de nekünk data url-ként kell (readAsDataURL).
Ezt meg egyből küldhetjük is tovább a fennebb már darabjaiban bemutatott draw függvénynek, ami betölti a képet, átönti a tartalmát a canvasba, nyit egy workert, feldolgoztatja vele a képet, kerék alá teszi, onnan is kiveszi. A kész képet a canvasból pedig ugyanúgy data url-ként tudjuk kiszedni, ezt aztán be tudjuk rakni az imagewell forrásának.
És mi van ha nem desktopról akarsz behúzni fájlt?
Akkor meg kell nézned az event.dataTransfer.types-ban, hogy kaptál-e olyan MIME típust, amire szükséged van. Például ha böngészőablakból húzol át bármit is, text/html-t fogsz kapni. Ha nem lenne teljesen idióta a canvas origin-cleanje, tudnánk ilyet csinálni:
De mivel a másik böngészőlapról behúzott képnek más az originje, ezért elkezd rinyálni, mi pedig nem tudunk semmit se tenni. Fenébe.
Vissza a desktopra
Meg tudod mondani, mi történjen, ha kihúzzák az ablakból az elemedet. Emlékszel fennebb, ahogy meg kellett nézned, van-e olyan MIME típus, amivel tudsz mit kezdeni? Na, itt pont annak a fordítottját kell csinálnod: össze kell állítanod egy batyut, benne az összes (szerinted) lehetséges formátumát a kihúzott elemnek. A 280 Slides egyik fejlesztője rinyáltjegyezte meg, hogy az összes exportálandó formátumot egyszerre kell lerenderelned, csak hogy aztán ezeket egy kivételével mind eldobják, amikor célbeér. Ez lassú és pazarló megoldás, amikor elég lenne a célbaérés után lerenderelni azt az egyfélét, amire valójában szükség van. (Zárójel: ha jól értem, és javítsatok ki kérlek, ez a Macintosh-féle D&D amit ők szeretnének, amit meg az Internet Exploreren keresztül örököltünk a böngészőbe, az a Windowsos, ami már a desktopon se volt jó élmény.)
Egyetlen korlát,you can have any color as long as it’s black: text/*-on kívül nem igazán fogják engedni a böngészők, hogy bármit kihúzz. Képfájlra text/uri-list formátumot javasol az MDC, valahogy így:
Egyetlen gond van: a data url-es képünkkel nem tud mit kezdeni a desktop (legalábbis Linuxon és Macen nem volt szerencsém). Marad a Jobbkatt-Mentés másként, és igen, ezért dolgoztunk ennyit. Vagy én nem látok valami egyértelműt?
Tada.wav
És körbeértünk: drag, drop, fájlbetöltés, háttérben futó javascript, rajzolás. Ha ez mind működik, szinte teljesen el tudjuk felejteni, hogy még mindig a böngészőben vagyunk és már-már belelobog a hajunk a lebegőautós, holdbázisos, mindenre képes böngészős jövőbe.
Aztán belebotlunk egy same-origin korlátba és ráébredünk, hogy krumplipüréből akarunk polcot építeni. De ne rontsuk el az illúziót, mert kezdek belejönni a krumplipürébe.
