Upload obrázků pomocí HTML5

HTML5 přináší několik zajímavých API. Při použití v kombinaci s elementem <canvas> je možné vytvořit naprosto úžasný formulář k nahrávání obrázků. V tomto článku si ukážeme jak. Popsaná API fungují dobře pro Firefox 4 i pro prohlížeče postavené na Webkitu. Bohužel pro IE bude třeba použít klasický formulář.

Článek vychází z anglického originálu How to develop a HTML5 image uploader, jehož autorem je Paul Rouget a který vyšel na stránkách Mozilla Hacks pod licencí CC-BY-SA. Pod stejnou licencí je k dispozici i tento překlad.

Získávání obrázků

Drag and Drop

K zadávání souborů pro upload slouží element <input type="file">. Mnohem lepší je umožnit uživatelům obrázky prostě přetáhnout přímo na vaši webovou stránku.

Autor napsal podrobný článek o implementaci drag-and-drop na vašich webových stránkách. Můžete se také podívat na tutoriál drag-and-drop od Mozilly.

Vícenásobný výběr

Můžete uživatelům povolit vybrat víc souborů najednou pomocí konstrukce

<input type="file" multiple>

Více o tomto postupu naleznete v článku o vícenásobném výběru souborů od téhož autora.

Zpracování souborů

Použití File API

(Detaily naleznete v dokumentaci k File API.) 

Nejprve si zjistíme seznam souborů vložených pomocí <input> elementu nebo prostým přetažením:

// pomocí input elementu
var filesToUpload = input.files;
// pomocí drag-and-drop
function onDrop(e) {
  filesToUpload = e.dataTransfer.files;
}

Ověříme, zda se skutečně jedná o obrázky:

if (!file.type.match(/image.*/)) {
  // tento soubor není obrázek
};

Zobrazení náhledů

Máme dvě možnosti. Buď použijeme FileReader (z File API), nebo novější metodu createObjectURL() .

createObjectURL()

var img = document.createElement("img");
img.src = window.URL.createObjectURL(file);

FileReader

var img = document.createElement("img");
var reader = new FileReader();
reader.onload = function(e) {img.src = e.target.result}
reader.readAsDataURL(file);

Použití canvasu

Jakmile máme surová data obrázku v <img> elementu, můžeme jej před dalším zpracováním vykreslit do elementu <canvas>.

var ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0);

Zmenšení obrázku

Někteří lidé nahrávají obrázky přímo z fotoaparátu. Rozlišeních takových obrázků, nehledě na jejich velikost, může být pro dané účely zbytečně vysoké. Pro změnu velikosti existuje velice jednoduchý trik. Obrázek stačí vykreslit do menšího canvasu (např. 800×600). Nesmíte ovšem zapomenout na správný poměr stran.

var MAX_WIDTH = 800;
var MAX_HEIGHT = 600;
var width = img.width;
var height = img.height;

if (width > height) {
  if (width > MAX_WIDTH) {
    height *= MAX_WIDTH / width;
    width = MAX_WIDTH;
  }
} else {
  if (height > MAX_HEIGHT) {
    width *= MAX_HEIGHT / height;
    height = MAX_HEIGHT;
  }
}
canvas.width = width;
canvas.height = height;
var ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0, width, height);

Úpravy obrázku

Teď, když máme obrázek v canvasu, jsou možnosti dalších úprav v podstatě neomezené. Můžeme například aplikovat filtr sépie:

var imgData = ctx.createImageData(width, height);
var data = imgData.data;
var pixels = ctx.getImageData(0, 0, width, height);
for (var i = 0, ii = pixels.data.length; i < ii; i += 4) {
    var r = pixels.data[i + 0];
    var g =pixels.data[i + 1];
    var b = this.pixels.data[i + 2];
    data[i + 0] = (r * .393) + (g *.769) + (b * .189);
    data[i + 1] = (r * .349) + (g *.686) + (b * .168)
    data[i + 2] = (r * .272) + (g *.534) + (b * .131)
    data[i + 3] = 255;
}
ctx.putImageData(imgData, 0, 0);

Odeslání na server pomocí XMLHttpRequest

Jakmile máme obrázky od uživatele načtené a zpracované, je potřeba je poslat na server.

Jak poslat canvas

Opět máme dvě možnosti. Můžeme převést canvas na datové URL, nebo (ve Firefoxu) vytvořit z canvasu  soubor.

canvas.toDataURL()

var dataurl = canvas.toDataURL("image/png");

Převod canvasu na soubor

var file = canvas.mozGetAsFile("foo.png");

Atomické nahrávání souborů

Nechte uživatele poslat soubor nebo více souborů najednou.

Průběh náhrávání souborů na server

Použijeme událostí na objektu uploadu ke zobrazení průběhu.

xhr.upload.addEventListener("progress", function(e) {
  if (e.lengthComputable) {
    var percentage = Math.round((e.loaded * 100) / e.total);
    // úprava průběhu
}, false);

Použití FormData

Samotné odeslání dat můžeme jednoduše provést pomocí xhr.send(file). Může se ovšem stát, že budete chtít k obrázkům přidat nějaké další informace (např. jméno, klíč apod.).

V takovém případě vytvořte zprávu typu multipart/form-data pomocíFormData objektu. (Viz Firefox 4: jednodušší JS zpracování formulářů pomocí FormData.)

var fd = new FormData();
fd.append("name", "paul");
fd.append("image", canvas.mozGetAsFile("foo.png"));
fd.append("key", "××××××××××××");
var xhr = new XMLHttpRequest();
xhr.open("POST", "http://your.api.com/upload.json");
xhr.send(fd);

Otevřené API

Možná budete chtít zpřístupnit svou službu i ostatním.Na co je důležité nezapomenout?

Přístup z jiných domén

Ve standardním nastavení je vaše API dostupné pouze z vaší domény. Chcete-li jej zpřístupnit i ostatním, musíte to povolit v HTTP hlavičce:

Access-Control-Allow-Origin: *

Případně přístup omezit na několik vybraných domén.

Přečtěte si taky Cross-Origin Resource Sharing nebo článek Cross Site XHR zde na Zdrojáku.

postMessage

(Díky Danielu Goodwinovi za tento tip.)

Můžete naslouchat zprávám poslaným skrz postMessage . Můžete tak lidem umožnit použít vaše API skrz postMessage:

document.addEventListener("message", function(e){
    // parametery pomocí e.data
    var key = e.data.key;
    var name = e.data.name;
    var dataurl = e.data.dataurl;
    // upload
}
// jakmile je vše odesláno, přesměrujte uživatele pomocí postMessage na původní URL

A to je vše, přátelé. Podělte se o další tipy v komentářích.

Věděli jste, že nám můžete zasílat zprávičky? (Jen pro přihlášené.)

Komentáře: 25

Přehled komentářů

Jakub Vrána Regulární výraz
rooobertek Výber viacerých súborov
fos4 Message
chleba dupla
Michal Wiglasz Re: dupla
Martin Malý Re: dupla
enumag K čemu ten canvas?
Villlém Re: K čemu ten canvas?
Mordae Re: K čemu ten canvas?
srigi Re: K čemu ten canvas?
enumag Re: K čemu ten canvas?
pkroh Re: K čemu ten canvas?
enumag Re: K čemu ten canvas?
Mordae Re: K čemu ten canvas?
enumag Re: K čemu ten canvas?
josefrichter Re: K čemu ten canvas?
enumag Re: K čemu ten canvas?
Michal Wiglasz Re: K čemu ten canvas?
enumag Re: K čemu ten canvas?
dasim Ukázky
antaresin Re: Ukázky
Martin Malý Re: Ukázky
korCZis Re: Ukázky
renergy "Periodická tabulka"
manakmichal dnd a chrome
Zdroj: https://www.zdrojak.cz/?p=3420