FrontTalks: Константин Лебедев (Mail.ru), File API: обработка файлов...

Post on 16-Jun-2015

1.179 views 12 download

description

История появления open source библиотеки для работы с файлами. Создание предпросмотра изображений на клиенте. Чтение файлов (exif, id3 и т.п.), загрузка результата на сервер. Всё это работает даже в IE6.

Transcript of FrontTalks: Константин Лебедев (Mail.ru), File API: обработка файлов...

FileAPI: Загрузка и обработка файловКонстантин Лебедев

https://github.com/mailru/FileAPI

2

Что было

3

Что было

4

Что было

Flash

5

Что было

HTML/JS

6

• Множественный выбор файлов

• Получение информации (название, размер, тип)

• Создание пред-просмотра на клиенте

• Масштабирование, кадрирование и поворот

• Загрузка на сервер + CORS

Требования

7

• Не зависеть от вёрстки

• Никакой бизнес-логики

• Расширяемость

• Самодостаточность

Требования

Error #2038

10%

Error #2038

5%

11

Поддержка

• Chrome 10+• FireFox 3.6+• Opera 11.1+• Safari 5.4+

12

13

ПОЛУЧЕНИЕ СПИСКАФАЙЛОВ

14

HTML5

<input id="file" type="file" multiple /><script>

var input = document.getByElementId("file"); input.addEventListener("change", function (){

var files = input.files; }, false);

</script>

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

Flash

FLASH

18

Flash

FLASH

19

Flash

FLASH

Flash --> jsFunc([{ id: "346515436346", // уникальный идентификатор

name: "hello-world.png", // название файла type: "image/png", // mime-type

size: 43325 // рамер}, {

// etc.}])

Взаимодействие

flash.cmd("imageTransform", { id: "346515436346", // идентификатор файла

matrix: { }, // "матрица" трансформации callback: "__UNIQ_NAME__" // размер

});

21

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); });

</script>

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 (evt){

var files = FileAPI.getFiles(evt); });

</script>

23

ФИЛЬТРАЦИЯ

FileReader

• readAsDataURL(file)

• readAsArrayBuffer(file)

• readAsText(file[, encoding])

25

Фильтрация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) — убрать ссылку

35

• crop(x, y, width, height) — кадрирование

• resize(width[, height]) — масштабирование

• rotate(deg) — поворот

• preview(width, height) — кадрирует и масштабирует

• get(callback) — получить итоговое изображение

FileAPI.Image

36

Matrix{ // параметры фрагмента оригинала

sx: Number, sy: Number, sw: Number, sh: Number,

// требуемые размеры dw: Number, dh: Number, deg: Number

}

37

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);

54

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'));

55

Загрузка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){}});

56

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:

58

XHR

var xhr = FileAPI.upload({ … });

59

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 архитекторk.lebedev@corp.mail.ru

https://github.com/mailru/FileAPI