константин лебедев
TRANSCRIPT
FileAPI: Загрузка и обработка файлов
Константин Лебедевhttps://github.com/mailru/FileAPI
3
Что было
4
Что было
5
Что было
Flash
6
Что было
HTML/JS
7
• Множественный выбор файлов
• Получение информации (название, размер, тип)
• Создание пред-просмотра на клиенте
• Масштабирование, кадрирование и поворот
• Загрузка на сервер + CORS
Требования
8
• Не зависеть от вёрстки
• Никакой бизнес-логики
• Расширяемость
• Самодостаточность
Требования
Error #2038
10%
Error #2038
5%
12
Поддержка
• Chrome 10+• FireFox 3.6+• Opera 11.1+• Safari 5.4+
13
14
ПОЛУЧЕНИЕ СПИСКАФАЙЛОВ
15
HTML5
<input id="file" type="file" multiple /><script>
var input = document.getByElementId("file");input.addEventListener("change", function (){
var files = input.files;}, false);
</script>
16
HTML5
<input id="file" type="file" multiple /><script>
var input = document.getByElementId("file");input.addEventListener("change", function (){
var files = input.files;}, false);
</script>
17
HTML5
<input id="file" type="file" multiple /><script>
var input = document.getByElementId("file");input.addEventListener("change", function (){
var files = input.files;}, false);
</script>
18
Flash
FLASH
19
Flash
FLASH
20
Flash
FLASH
Flash --> jsFunc([{id: "346515436346", // уникальный идентификаторname: "hello-world.png", // название файлаtype: "image/png", // mime-typesize: 43325 // рамер
}, { // etc.}])
Взаимодействие
flash.cmd("imageTransform", {id: "346515436346", // идентификатор файлаmatrix: { }, // "матрица" трансформацииcallback: "__UNIQ_NAME__" // размер
});
22
API
<span class="js-fileapi-wrapper" style="position: relative"><input id="file" type="file" multiple />
</span><script>
var input = document.getByElementId("file");FileAPI.event.on(input, "change", function (){
var files = FileAPI.getFiles(input);}, false);
</script>
23
API
<span class="js-fileapi-wrapper" style="position: relative"><input id="file" type="file" multiple />
</span><script>
var input = document.getByElementId("file");FileAPI.event.on(input, "change", function (evt){
var files = FileAPI.getFiles(evt);}, false);
</script>
24
ФИЛЬТРАЦИЯ
FileReader
• readAsDataURL(file)
• readAsBinaryString(file)
• readAsArrayBuffer(file)
• readAsText(file[, encoding])
26
Фильтрация
FileAPI.filterFiles(files, function (file, info){
return file.size < 10 * FileAPI.MB;
}, function (files, ignore){
if( files.length > 0 ){
// ...
}
});
FileAPI.addInfoReader(/^audio/, function (file, callback){
// собираем нужную информацию
// и возвращаем её
callback(
false, // или текст ошибки
{ artist: "...", album: "...", title: "...", ... }
);
});
Информация о файле
FileAPI.getInfo(audioFile, function (err, tags){
if( !err ){
var li = document.createElement("li");
li.innerHTML = tags.artist +" – "+ tags.title;
ul.appendChild(li);
}
});
Информация о файле
ПРЕДПРОСМОТР
Предпросмотр
DataURI
Предпросмотр
DataURI
Base64
Предпросмотр
DataURI
Base64
“data:image/png;base64,” + Base64
<img/>
Предпросмотр
DataURI
Base64
“data:image/png;base64,” + Base64
Base64
<img/>
Предпросмотр
HTML5
• FileReader.readAsDataURL(file) — позволяет
прочесть содержимое файла как DataURL
• URL.createObjectURL(file) — создает ссылку,
указывающую на файл
Предпросмотр
HTML5
• FileReader.readAsDataURL(file) — позволяет
прочесть содержимое файла как DataURL
• URL.createObjectURL(file) — создает ссылку,
указывающую на файл
• URL.revokeObjectURL(file) — убрать ссылку
36
• crop(x, y, width, height) — кадрирование
• resize(width[, height]) — масштабирование
• rotate(deg) — поворот
• preview(width, height) — кадрирует и масштабирует
• get(callback) — получить итоговое изображение
FileAPI.Image
37
Matrix
{ // параметры фрагмента оригинала sx: Number,sy: Number,sw: Number,sh: Number,
// требуемые размеры
dw: Number,dh: Number,deg: Number
}
38
FileAPI.Image
FileAPI.Image(imageFle).crop(300, 300).resize(100, 100).get(function (err, img){
if( !err ){images.appendChild(img);
}})
;
Сжатие
5197х4987
Сжатие
Сжатие
5197х4987 2598х2493
Сжатие x 2
5197х4987 2598х2493 1299х1246
Сжатие x 5
5197х4987 2598х2493 1299х1246
100х100
…
Сжатие
Серия
ЗАГРУЗКА ФАЙЛОВ
• Без обновления страницы
• Процесс загрузки
• Получить ответ от сервера
Требования
Загрузка
<form action="/upload" method="post" enctype="multipart/form-data">
<input name="files" type="file" /><input name="foo" value="bar" type="hidden" />
</form>
Загрузка
<form target="__UNIQ__" action="/upload" method="post" enctype="multipart/form-data">
<iframe name="__UNIQ__"></iframe><input name="files" type="file" /><input name="foo" value="bar" type="hidden" />
</form>
Уникальный идентификатор
Загрузка
XMLHttpRequest level 2
FormData
Загрузка
// собираем данные для отправки
var form = new FormDataform.append("foo", "bar");form.append("attach", file);
// отправояем на сервер
var xhr = new XMLHttpRequest;xhr.open("POST", "/upload", true);xhr.send(form)
Загрузка
// собираем данные для отправки
var form = new FormDataform.append("foo", "bar");form.append("attach", file);
// отправляем на сервер
var xhr = new XMLHttpRequest;xhr.open("POST", "/upload", true);xhr.send(form)
ЗагрузкаcanvasToBlob(canvas, function (blob){
// собираем данные для отправки
var form = new FormDataform.append("foo", "bar");form.append("attach", blob, "filename.png");
// отправляем на сервер
var xhr = new XMLHttpRequest;xhr.open("POST", "/upload", true);xhr.send(form)
});
Загрузка
<cavnas/> DataURL
dataURL = canvas.toDataURL(“image/png”);
Загрузка
<cavnas/> DataURL Base64
dataURL = canvas.toDataURL(“image/png”);
base64 = dataURL.replace(/^data:[^,]+,/, “”);
Загрузка
<cavnas/> DataURL Base64
BinaryString
dataURL = canvas.toDataURL(“image/png”);
base64 = dataURL.replace(/^data:[^,]+,/, “”);
binaryString = window.atob(base64);
56
Multipart
var uniq = '1234567890';var xhr = new XMLHttpRequest;xhr.open('POST', '/upload', true);xhr.setRequestHeader('Content-Type', 'multipart/form-data; boundary=_'+uniq);xhr.sendAsBinary([ '--_'+ uniq, 'Content-Disposition: form-data; name="my-file"; filename="hello-world.png"', 'Content-Type: image/png', '', binaryString, '--_'+ uniq +'--'].join('\r\n'));
57
Загрузка
var xhr = FileAPI.upload({ url: '/upload', data: { foo: 'bar' }, headers: { 'Session-Id': '...' }, files: { images: imageFiles, others: otherFiles }, imageTransform: { maxWidth: 1024, maxHeight: 768 }, upload: function (xhr){}, progress: function (event, file){}, complete: function (err, xhr, file){}, fileupload: function (file, xhr){}, fileprogress: function (event, file){}, filecomplete: function (err, xhr, file){}});
58
var xhr = FileAPI.upload({ url: '/upload', data: { foo: 'bar' }, headers: { 'Session-Id': '...' }, files: { images: imageFiles, others: otherFiles }, imageTransform: { maxWidth: 1024, maxHeight: 768 }, upload: function (xhr){}, progress: function (event, file){}, complete: function (err, xhr, file){}, fileupload: function (file, xhr){}, fileprogress: function (event, file){}, filecomplete: function (err, xhr, file){}});
Загрузка
Загрузка
{
huge: { maxWidth: 800, maxHeight: 600, rotate: 90 },
medium: { width: 320, height: 240, preview: true },
small: { width: 100, height: 120, preview: true }
}
imageTransform:
60
XHR
var xhr = FileAPI.upload({ … });
61
XHR
var xhr = FileAPI.upload({ … });
• status — HTTP status code
• statusText — HTTP status text
• responseText — ответ сервера
• getResponseHeader(name) — получить заголовок ответа сервера
• getAllResponseHeaders() — получить все заголовки
• abort() — отменить загрузку
Drag’n’Drop
Перетащите файлы сюда
<div class="dropzone"></div>
Drag’n’Drop
4
<div class="dropzone dropzone_hover"></div>
Drag’n’Drop<div id="el" class="dropzone"></div><script> var el = document.getElementById("el"); FileAPI.event.dnd(el, function (over){ if( ever ){ el.classList.add("dropzone_hover"); } else { el.classList.remove("dropzone_hover"); } }, function (files){ uploadFiles(files); }); </script>
4
Drag’n’Drop<div id="el" class="dropzone"></div><script> var el = document.getElementById("el");
FileAPI.event.dnd(el, function (over){ if( ever ){ el.classList.add("dropzone_hover"); } else { el.classList.remove("dropzone_hover"); } }, function (files){ uploadFiles(files); }); </script>
4
Drag’n’Drop<div id="el" class="dropzone"></div><script> var el = document.getElementById("el");
FileAPI.event.dnd(el, function (over){ if( ever ){ el.classList.add("dropzone_hover"); } else { el.classList.remove("dropzone_hover"); } }, function (files){ uploadFiles(files); }); </script>
4
Drag’n’Drop<div id="el" class="dropzone"></div><script> var el = document.getElementById("el");
FileAPI.event.dnd(el, function (over){ if( ever ){ el.classList.add("dropzone_hover"); } else { el.classList.remove("dropzone_hover"); } }, function (files){ uploadFiles(files); }); </script>
4
Drag’n’Drop
function uploadFiles(dropFiles){ FileAPI.upload({ url: "/upload", files: { attaches: dropFiles }, complete: function (err, xhr){ if( !err ){ // файлы загружены } } }); }
4
Константин ЛебедевJavaScript архитектор[email protected]
https://github.com/mailru/FileAPI