Upload
yandex
View
1.179
Download
12
Embed Size (px)
DESCRIPTION
История появления open source библиотеки для работы с файлами. Создание предпросмотра изображений на клиенте. Чтение файлов (exif, id3 и т.п.), загрузка результата на сервер. Всё это работает даже в IE6.
Citation preview
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 архитектор[email protected]
https://github.com/mailru/FileAPI