SlideShare a Scribd company logo
1 of 87
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.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 
<img/> 
“data:image/png;base64,” + Base64
Предпросмотр 
DataURI 
Base64 
<img/> 
“data:image/png;base64,” + Base64
Предпросмотр 
HTML5 
• FileReader.readAsDataURL(file) — позволяет 
прочесть содержимое файла как DataURL 
• URL.createObjectURL(file) — создает ссылку, 
указывающую на файл
Предпросмотр 
HTML5 
• FileReader.readAsDataURL(file) — позволяет 
прочесть содержимое файла как DataURL 
• URL.createObjectURL(file) — создает ссылку, 
указывающую на файл 
• URL.revokeObjectURL(file) — убрать ссылку
34 
FileAPI.Image 
• crop(x, y, width, height) — кадрирование 
• resize(width[, height]) — масштабирование 
• rotate(deg) — поворот 
• preview(width, height) — кадрирует и масштабирует 
• get(callback) — получить итоговое изображение
35 
Matrix 
{ // параметры фрагмента оригинала 
sx: Number, 
sy: Number, 
sw: Number, 
sh: Number, 
// требуемые размеры 
dw: Number, 
dh: Number, 
deg: Number 
}
36 
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 FormData 
form.append("foo", "bar"); 
form.append("attach", file); 
// отправояем на сервер 
var xhr = new XMLHttpRequest; 
xhr.open("POST", "/upload", true); 
xhr.send(form)
Загрузка 
// собираем данные для отправки 
var form = new FormData 
form.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 FormData 
form.append("foo", "bar"); 
form.append("attach", blob, "filename.png"); 
// отправляем на сервер 
var xhr = new XMLHttpRequest; 
xhr.open("POST", "/upload", true); 
xhr.send(form) 
});
Загрузка 
dataURL = canvas.toDataURL(“image/png”); 
<cavnas/> DataURL
Загрузка 
dataURL = canvas.toDataURL(“image/png”); 
base64 = dataURL.replace(/^data:[^,]+,/, “”); 
<cavnas/> DataURL Base64
Загрузка 
dataURL = canvas.toDataURL(“image/png”); 
base64 = dataURL.replace(/^data:[^,]+,/, “”); 
binaryString = window.atob(base64); 
<cavnas/> DataURL Base64 
BinaryString
53 
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('rn'));
54 
Загрузка 
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){} 
});
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){} 
});
Загрузка 
imageTransform: 
{ 
huge: { maxWidth: 800, maxHeight: 600, rotate: 90 }, 
medium: { width: 320, height: 240, preview: true }, 
small: { width: 100, height: 120, preview: true } 
}
57 
XHR 
var xhr = FileAPI.upload({ … });
58 
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 
<div class="dropzone dropzone_hover"></div> 
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 
<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
Спустя год 
• Закрыто более 100 github issue 
• GruntJS (JSLint, QUnit + PhantomJS, Uglify) 
• Улучшена работа с изображениями 
• Добавлена поддержка работы с веб-камерой 
• Разработан jQuery plugin для типовых задач 
• Улучшена документация (+ примеры)
OVERLAYS
Overlay 
FileAPI.Image(imageFile) 
.overlay([{ 
x: 10 
, y: 10 
, src: "/i/watermark.png" 
, rel: FileAPI.Image.RITGHT_BOTTOM 
, opacity: 0.85 
]) 
.get(function (err/**String*/, img/**HTMLElement*/)({ /*__*/ }) 
;
Overlay 
var xhr = FileAPI.upload({ 
url: "...", 
files: images, 
imageTransform: { 
overlay: { /* options */ } 
} 
});
FILTERS
Filters 
FileAPI.Image(imageFile) 
.filter(function (canvas, doneFn){ 
// processing... 
doneFn(); 
}) 
.get(function (err/**String*/, img/**HTMLElement*/)({ 
/*__*/ 
}) 
;
CamanJS
Filters + CamanJS 
FileAPI.Image(imageFile) 
.filter("hazyDays") 
.get(function (err/**String*/, 
img/**HTMLElement*/)({ 
/*__*/ 
}) 
;
WebCam
WebCam 
navigator.getUserMedia( constraints, success, error ); 
— запросить разрешение на использование 
микрофона и/или камеры
WebCam 
navigator.getUserMedia({ video: true }, function (stream){ 
var video = document.getElementById("webcam"); 
var streamSrc = URL.createObjectURL(stream); 
video.src = streamUrl; 
});
WebCam 
navigator.getUserMedia({ video: true }, function (stream){ 
var video = document.getElementById("webcam"); 
var streamSrc = URL.createObjectURL(stream); 
video.src = streamUrl; 
});
WebCam 
function onTakeShot(){ 
var video = document.getElementById("webcam"); 
var canvas = document.createElement("canvas"); 
var ctx = canvas.getContext("2d"); 
canvas.width = video.videoWidth; 
canvas.height = video.videoHeight; 
ctx.drawImage(video, 0, 0); 
}
FileAPI.Camera 
var el = document.getElementById("webcam"); 
FileAPI.Camera.publish(el, function (cam){ 
});
FileAPI.Camera 
var el = document.getElementById("webcam"); 
FileAPI.Camera.publish(el, function (cam){ 
FileAPI.event.on(btn, "click", function (){ 
var shot = cam.shot(); // FileAPI.Image instance 
FileAPI.upload({ url: "...", files: shot }); 
}); 
});
jQuery.FileAPI 
• «Одной кнопкой» — выбрать и автоматически загрузить файл 
• «Ограничения» — минимальный/максимальный размер как 
файла, так и изображения, по ширине и высоте 
• «Работа с очередью» — сортировка и фильтрация очереди 
загрузки файлов 
• «Изображения» — предпросмотр, поворот и кадрирование 
• «Интерфейс» — гибкая и прозрачная настройка интерфейса 
• А также Drag’n’Drop и WebCam
jQuery.FileAPI
jQuery.FileAPI
jQuery.FileAPI
jQuery.FileAPI
jQuery.FileAPI
https://github.com/mailru/FileAPI 
Константин Лебедев 
@ibnRubaXa 
k.lebedev@corp.mail.ru

More Related Content

What's hot

Школа-студия разработки для iOS. Лекция 4. Работа с данными
Школа-студия разработки для iOS. Лекция 4. Работа с даннымиШкола-студия разработки для iOS. Лекция 4. Работа с данными
Школа-студия разработки для iOS. Лекция 4. Работа с даннымиГлеб Тарасов
 
JS утиліти WordPress на практиці
JS утиліти WordPress на практиціJS утиліти WordPress на практиці
JS утиліти WordPress на практиціShtrih Sruleg
 
Игорь Любин - PowerShell - ConfeT&QA 2011
Игорь Любин - PowerShell - ConfeT&QA 2011Игорь Любин - PowerShell - ConfeT&QA 2011
Игорь Любин - PowerShell - ConfeT&QA 2011ilyubin
 
CodeFest 2013. Никонов Г. — Как мы разрабатываем приложения для Windows Phone...
CodeFest 2013. Никонов Г. — Как мы разрабатываем приложения для Windows Phone...CodeFest 2013. Никонов Г. — Как мы разрабатываем приложения для Windows Phone...
CodeFest 2013. Никонов Г. — Как мы разрабатываем приложения для Windows Phone...CodeFest
 
Роман Акинфеев «Разработка RESTful API with all bells and whistles»
Роман Акинфеев «Разработка RESTful API with all bells and whistles»Роман Акинфеев «Разработка RESTful API with all bells and whistles»
Роман Акинфеев «Разработка RESTful API with all bells and whistles»DevDay
 
Drupal 7 и history.js или как ajax инфицировать сайт
Drupal 7 и history.js или как ajax инфицировать сайтDrupal 7 и history.js или как ajax инфицировать сайт
Drupal 7 и history.js или как ajax инфицировать сайтDrupalCamp Kyiv Рысь
 
Web осень 2013 лекция 5
Web осень 2013 лекция 5Web осень 2013 лекция 5
Web осень 2013 лекция 5Technopark
 
Интуит. Разработка приложений для iOS. Лекция 8. Работа с данными
Интуит. Разработка приложений для iOS. Лекция 8. Работа с даннымиИнтуит. Разработка приложений для iOS. Лекция 8. Работа с данными
Интуит. Разработка приложений для iOS. Лекция 8. Работа с даннымиГлеб Тарасов
 
The Old New ASP.NET
The Old New ASP.NETThe Old New ASP.NET
The Old New ASP.NETVitaly Baum
 
LDAP in infrastructure (RootConf 2009)
LDAP in infrastructure (RootConf 2009)LDAP in infrastructure (RootConf 2009)
LDAP in infrastructure (RootConf 2009)Sergey Skvortsov
 
Web осень 2013 лекция 3
Web осень 2013 лекция 3Web осень 2013 лекция 3
Web осень 2013 лекция 3Technopark
 
JDI: Автоматизировать проще, чем кажется
JDI: Автоматизировать проще, чем кажетсяJDI: Автоматизировать проще, чем кажется
JDI: Автоматизировать проще, чем кажетсяSQALab
 
Михаил Давыдов — Транспорт, Ajax
Михаил Давыдов — Транспорт, AjaxМихаил Давыдов — Транспорт, Ajax
Михаил Давыдов — Транспорт, AjaxYandex
 
Разработка крупного Standalone проекта на юнити: улучшаем производительность
Разработка крупного Standalone проекта на юнити: улучшаем производительностьРазработка крупного Standalone проекта на юнити: улучшаем производительность
Разработка крупного Standalone проекта на юнити: улучшаем производительностьВадим Воробьев
 
«Highload блоки и новое api к ним»
«Highload блоки и новое api к ним» «Highload блоки и новое api к ним»
«Highload блоки и новое api к ним» Гузель Рахимова
 
JavaScript Базовый. Занятие 07.
JavaScript Базовый. Занятие 07.JavaScript Базовый. Занятие 07.
JavaScript Базовый. Занятие 07.Igor Shkulipa
 
Хранение, обработка и отдача статики с использованием \Zend\File. Опыт социал...
Хранение, обработка и отдача статики с использованием \Zend\File. Опыт социал...Хранение, обработка и отдача статики с использованием \Zend\File. Опыт социал...
Хранение, обработка и отдача статики с использованием \Zend\File. Опыт социал...zfconfua
 

What's hot (20)

Школа-студия разработки для iOS. Лекция 4. Работа с данными
Школа-студия разработки для iOS. Лекция 4. Работа с даннымиШкола-студия разработки для iOS. Лекция 4. Работа с данными
Школа-студия разработки для iOS. Лекция 4. Работа с данными
 
JS утиліти WordPress на практиці
JS утиліти WordPress на практиціJS утиліти WordPress на практиці
JS утиліти WordPress на практиці
 
Укрощение XML
Укрощение XMLУкрощение XML
Укрощение XML
 
Игорь Любин - PowerShell - ConfeT&QA 2011
Игорь Любин - PowerShell - ConfeT&QA 2011Игорь Любин - PowerShell - ConfeT&QA 2011
Игорь Любин - PowerShell - ConfeT&QA 2011
 
BlueEyes russian
BlueEyes russianBlueEyes russian
BlueEyes russian
 
CodeFest 2013. Никонов Г. — Как мы разрабатываем приложения для Windows Phone...
CodeFest 2013. Никонов Г. — Как мы разрабатываем приложения для Windows Phone...CodeFest 2013. Никонов Г. — Как мы разрабатываем приложения для Windows Phone...
CodeFest 2013. Никонов Г. — Как мы разрабатываем приложения для Windows Phone...
 
Роман Акинфеев «Разработка RESTful API with all bells and whistles»
Роман Акинфеев «Разработка RESTful API with all bells and whistles»Роман Акинфеев «Разработка RESTful API with all bells and whistles»
Роман Акинфеев «Разработка RESTful API with all bells and whistles»
 
Drupal 7 и history.js или как ajax инфицировать сайт
Drupal 7 и history.js или как ajax инфицировать сайтDrupal 7 и history.js или как ajax инфицировать сайт
Drupal 7 и history.js или как ajax инфицировать сайт
 
Drupal 7 and History.js
Drupal 7 and History.jsDrupal 7 and History.js
Drupal 7 and History.js
 
Web осень 2013 лекция 5
Web осень 2013 лекция 5Web осень 2013 лекция 5
Web осень 2013 лекция 5
 
Интуит. Разработка приложений для iOS. Лекция 8. Работа с данными
Интуит. Разработка приложений для iOS. Лекция 8. Работа с даннымиИнтуит. Разработка приложений для iOS. Лекция 8. Работа с данными
Интуит. Разработка приложений для iOS. Лекция 8. Работа с данными
 
The Old New ASP.NET
The Old New ASP.NETThe Old New ASP.NET
The Old New ASP.NET
 
LDAP in infrastructure (RootConf 2009)
LDAP in infrastructure (RootConf 2009)LDAP in infrastructure (RootConf 2009)
LDAP in infrastructure (RootConf 2009)
 
Web осень 2013 лекция 3
Web осень 2013 лекция 3Web осень 2013 лекция 3
Web осень 2013 лекция 3
 
JDI: Автоматизировать проще, чем кажется
JDI: Автоматизировать проще, чем кажетсяJDI: Автоматизировать проще, чем кажется
JDI: Автоматизировать проще, чем кажется
 
Михаил Давыдов — Транспорт, Ajax
Михаил Давыдов — Транспорт, AjaxМихаил Давыдов — Транспорт, Ajax
Михаил Давыдов — Транспорт, Ajax
 
Разработка крупного Standalone проекта на юнити: улучшаем производительность
Разработка крупного Standalone проекта на юнити: улучшаем производительностьРазработка крупного Standalone проекта на юнити: улучшаем производительность
Разработка крупного Standalone проекта на юнити: улучшаем производительность
 
«Highload блоки и новое api к ним»
«Highload блоки и новое api к ним» «Highload блоки и новое api к ним»
«Highload блоки и новое api к ним»
 
JavaScript Базовый. Занятие 07.
JavaScript Базовый. Занятие 07.JavaScript Базовый. Занятие 07.
JavaScript Базовый. Занятие 07.
 
Хранение, обработка и отдача статики с использованием \Zend\File. Опыт социал...
Хранение, обработка и отдача статики с использованием \Zend\File. Опыт социал...Хранение, обработка и отдача статики с использованием \Zend\File. Опыт социал...
Хранение, обработка и отдача статики с использованием \Zend\File. Опыт социал...
 

Similar to FileAPI 2.0

Yii: миграции и инсталляции
Yii: миграции и инсталляцииYii: миграции и инсталляции
Yii: миграции и инсталляцииPaul Klimov
 
Silverlight 4, есть ли жизнь на десктопе
Silverlight 4, есть ли жизнь на десктопеSilverlight 4, есть ли жизнь на десктопе
Silverlight 4, есть ли жизнь на десктопеAlex Tumanoff
 
Web осень 2012 лекция 4
Web осень 2012 лекция 4Web осень 2012 лекция 4
Web осень 2012 лекция 4Technopark
 
Web весна 2013 лекция 4
Web весна 2013 лекция 4Web весна 2013 лекция 4
Web весна 2013 лекция 4Technopark
 
Mihail davidov js-ajax
Mihail davidov js-ajaxMihail davidov js-ajax
Mihail davidov js-ajaxYandex
 
Как не утонуть в мегабайтах JS-кода
Как не утонуть в мегабайтах JS-кодаКак не утонуть в мегабайтах JS-кода
Как не утонуть в мегабайтах JS-кодаtfmailru
 
Взломать Web-сайт на ASP.NET? Сложно, но можно!
Взломать Web-сайт на ASP.NET? Сложно, но можно!Взломать Web-сайт на ASP.NET? Сложно, но можно!
Взломать Web-сайт на ASP.NET? Сложно, но можно!Vladimir Kochetkov
 
Web осень 2012 лекция 10
Web осень 2012 лекция 10Web осень 2012 лекция 10
Web осень 2012 лекция 10Technopark
 
Web весна 2013 лекция 10
Web весна 2013 лекция 10Web весна 2013 лекция 10
Web весна 2013 лекция 10Technopark
 
"Жизнь без интернета" Кувалдин Артём, Яндекс
"Жизнь без интернета" Кувалдин Артём, Яндекс"Жизнь без интернета" Кувалдин Артём, Яндекс
"Жизнь без интернета" Кувалдин Артём, Яндексit-people
 
Кэширование данных с помощью Service Worker
Кэширование данных с помощью Service WorkerКэширование данных с помощью Service Worker
Кэширование данных с помощью Service WorkerAndrew Smirnov
 
Web весна 2012 лекция 4
Web весна 2012 лекция 4Web весна 2012 лекция 4
Web весна 2012 лекция 4Technopark
 
Take more from Jquery
Take more from JqueryTake more from Jquery
Take more from JqueryMagento Dev
 
WebCamp: Developer Day: Parse'им бэкенд - Аким Халилов
WebCamp: Developer Day: Parse'им бэкенд - Аким ХалиловWebCamp: Developer Day: Parse'им бэкенд - Аким Халилов
WebCamp: Developer Day: Parse'им бэкенд - Аким ХалиловGeeksLab Odessa
 
Настройка Apache и PHP
Настройка Apache и PHPНастройка Apache и PHP
Настройка Apache и PHPVasya Petrov
 

Similar to FileAPI 2.0 (20)

course js day 4
course js day 4course js day 4
course js day 4
 
Jsfwdays 2013-2
Jsfwdays 2013-2Jsfwdays 2013-2
Jsfwdays 2013-2
 
Yii: миграции и инсталляции
Yii: миграции и инсталляцииYii: миграции и инсталляции
Yii: миграции и инсталляции
 
Silverlight 4, есть ли жизнь на десктопе
Silverlight 4, есть ли жизнь на десктопеSilverlight 4, есть ли жизнь на десктопе
Silverlight 4, есть ли жизнь на десктопе
 
Web осень 2012 лекция 4
Web осень 2012 лекция 4Web осень 2012 лекция 4
Web осень 2012 лекция 4
 
Web весна 2013 лекция 4
Web весна 2013 лекция 4Web весна 2013 лекция 4
Web весна 2013 лекция 4
 
Mihail davidov js-ajax
Mihail davidov js-ajaxMihail davidov js-ajax
Mihail davidov js-ajax
 
Sumin
SuminSumin
Sumin
 
Как не утонуть в мегабайтах JS-кода
Как не утонуть в мегабайтах JS-кодаКак не утонуть в мегабайтах JS-кода
Как не утонуть в мегабайтах JS-кода
 
Взломать Web-сайт на ASP.NET? Сложно, но можно!
Взломать Web-сайт на ASP.NET? Сложно, но можно!Взломать Web-сайт на ASP.NET? Сложно, но можно!
Взломать Web-сайт на ASP.NET? Сложно, но можно!
 
Web осень 2012 лекция 10
Web осень 2012 лекция 10Web осень 2012 лекция 10
Web осень 2012 лекция 10
 
Web весна 2013 лекция 10
Web весна 2013 лекция 10Web весна 2013 лекция 10
Web весна 2013 лекция 10
 
"Жизнь без интернета" Кувалдин Артём, Яндекс
"Жизнь без интернета" Кувалдин Артём, Яндекс"Жизнь без интернета" Кувалдин Артём, Яндекс
"Жизнь без интернета" Кувалдин Артём, Яндекс
 
JSSDK: Начало
JSSDK: НачалоJSSDK: Начало
JSSDK: Начало
 
Кэширование данных с помощью Service Worker
Кэширование данных с помощью Service WorkerКэширование данных с помощью Service Worker
Кэширование данных с помощью Service Worker
 
Web весна 2012 лекция 4
Web весна 2012 лекция 4Web весна 2012 лекция 4
Web весна 2012 лекция 4
 
Take more from Jquery
Take more from JqueryTake more from Jquery
Take more from Jquery
 
WebCamp: Developer Day: Parse'им бэкенд - Аким Халилов
WebCamp: Developer Day: Parse'им бэкенд - Аким ХалиловWebCamp: Developer Day: Parse'им бэкенд - Аким Халилов
WebCamp: Developer Day: Parse'им бэкенд - Аким Халилов
 
UWDC 2013, Yii2
UWDC 2013, Yii2UWDC 2013, Yii2
UWDC 2013, Yii2
 
Настройка Apache и PHP
Настройка Apache и PHPНастройка Apache и PHP
Настройка Apache и PHP
 

FileAPI 2.0

  • 1. FileAPI: Загрузка и обработка файлов
  • 6. 6 Требования • Множественный выбор файлов • Получение информации (название, размер, тип) • Создание пред-просмотра на клиенте • Масштабирование, кадрирование и поворот • Загрузка на сервер + CORS
  • 7. 7 Требования • Не зависеть от вёрстки • Никакой бизнес-логики • Расширяемость • Самодостаточность
  • 8.
  • 11. 11 Поддержка • Chrome 10+ • FireFox 3.6+ • Opera 11.1+ • Safari 5.4+
  • 12. 12
  • 14. 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. 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. 16 HTML5 <input id="file" type="file" multiple /> <script> var input = document.getByElementId("file"); input.addEventListener("change", function (){ var files = input.files; }, false); </script>
  • 19. 19 Flash FLASH Flash --> jsFunc([{ id: "346515436346", // уникальный идентификатор name: "hello-world.png", // название файла type: "image/png", // mime-type size: 43325 // рамер }, { // etc. }])
  • 20. Взаимодействие flash.cmd("imageTransform", { id: "346515436346", // идентификатор файла matrix: { }, // "матрица" трансформации callback: "__UNIQ_NAME__" // размер });
  • 21. 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. 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>
  • 24. FileReader • readAsDataURL(file) • readAsArrayBuffer(file) • readAsText(file[, encoding])
  • 25. 25 Фильтрация FileAPI.filterFiles(files, function (file, info){ return file.size < 10 * FileAPI.MB; }, function (files, ignore){ if( files.length > 0 ){ // ... } });
  • 26. Информация о файле FileAPI.getInfo(audioFile, function (err, tags){ if( !err ){ var li = document.createElement("li"); li.innerHTML = tags.artist +" – "+ tags.title; ul.appendChild(li); } });
  • 30. Предпросмотр DataURI Base64 <img/> “data:image/png;base64,” + Base64
  • 31. Предпросмотр DataURI Base64 <img/> “data:image/png;base64,” + Base64
  • 32. Предпросмотр HTML5 • FileReader.readAsDataURL(file) — позволяет прочесть содержимое файла как DataURL • URL.createObjectURL(file) — создает ссылку, указывающую на файл
  • 33. Предпросмотр HTML5 • FileReader.readAsDataURL(file) — позволяет прочесть содержимое файла как DataURL • URL.createObjectURL(file) — создает ссылку, указывающую на файл • URL.revokeObjectURL(file) — убрать ссылку
  • 34. 34 FileAPI.Image • crop(x, y, width, height) — кадрирование • resize(width[, height]) — масштабирование • rotate(deg) — поворот • preview(width, height) — кадрирует и масштабирует • get(callback) — получить итоговое изображение
  • 35. 35 Matrix { // параметры фрагмента оригинала sx: Number, sy: Number, sw: Number, sh: Number, // требуемые размеры dw: Number, dh: Number, deg: Number }
  • 36. 36 FileAPI.Image FileAPI.Image(imageFle) .crop(300, 300) .resize(100, 100) .get(function (err, img){ if( !err ){ images.appendChild(img); } }) ;
  • 40. Сжатие x 2 5197х4987 2598х2493 1299х1246
  • 41. Сжатие x 5 5197х4987 2598х2493 1299х1246 100х100
  • 44. Загрузка <form action="/upload" method="post" enctype="multipart/form-data"> <input name="files" type="file" /> <input name="foo" value="bar" type="hidden" /> </form>
  • 45. Загрузка <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> Уникальный идентификатор
  • 47. Загрузка // собираем данные для отправки var form = new FormData form.append("foo", "bar"); form.append("attach", file); // отправояем на сервер var xhr = new XMLHttpRequest; xhr.open("POST", "/upload", true); xhr.send(form)
  • 48. Загрузка // собираем данные для отправки var form = new FormData form.append("foo", "bar"); form.append("attach", file); // отправояем на сервер var xhr = new XMLHttpRequest; xhr.open("POST", "/upload", true); xhr.send(form)
  • 49. Загрузка canvasToBlob(canvas, function (blob){ // собираем данные для отправки var form = new FormData form.append("foo", "bar"); form.append("attach", blob, "filename.png"); // отправляем на сервер var xhr = new XMLHttpRequest; xhr.open("POST", "/upload", true); xhr.send(form) });
  • 50. Загрузка dataURL = canvas.toDataURL(“image/png”); <cavnas/> DataURL
  • 51. Загрузка dataURL = canvas.toDataURL(“image/png”); base64 = dataURL.replace(/^data:[^,]+,/, “”); <cavnas/> DataURL Base64
  • 52. Загрузка dataURL = canvas.toDataURL(“image/png”); base64 = dataURL.replace(/^data:[^,]+,/, “”); binaryString = window.atob(base64); <cavnas/> DataURL Base64 BinaryString
  • 53. 53 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('rn'));
  • 54. 54 Загрузка 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){} });
  • 55. 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. Загрузка imageTransform: { huge: { maxWidth: 800, maxHeight: 600, rotate: 90 }, medium: { width: 320, height: 240, preview: true }, small: { width: 100, height: 120, preview: true } }
  • 57. 57 XHR var xhr = FileAPI.upload({ … });
  • 58. 58 XHR var xhr = FileAPI.upload({ … }); • status — HTTP status code • statusText — HTTP status text • responseText — ответ сервера • getResponseHeader(name) — получить заголовок ответа сервера • getAllResponseHeaders() — получить все заголовки • abort() — отменить загрузку
  • 59. Drag’n’Drop <div class="dropzone"></div> Перетащите файлы сюда
  • 60. Drag’n’Drop <div class="dropzone dropzone_hover"></div> 4
  • 61. 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
  • 62. 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
  • 63. 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
  • 64. 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
  • 65. Drag’n’Drop function uploadFiles(dropFiles){ FileAPI.upload({ url: "/upload", files: { attaches: dropFiles }, complete: function (err, xhr){ if( !err ){ // файлы загружены } } }); } 4
  • 66. Спустя год • Закрыто более 100 github issue • GruntJS (JSLint, QUnit + PhantomJS, Uglify) • Улучшена работа с изображениями • Добавлена поддержка работы с веб-камерой • Разработан jQuery plugin для типовых задач • Улучшена документация (+ примеры)
  • 68. Overlay FileAPI.Image(imageFile) .overlay([{ x: 10 , y: 10 , src: "/i/watermark.png" , rel: FileAPI.Image.RITGHT_BOTTOM , opacity: 0.85 ]) .get(function (err/**String*/, img/**HTMLElement*/)({ /*__*/ }) ;
  • 69. Overlay var xhr = FileAPI.upload({ url: "...", files: images, imageTransform: { overlay: { /* options */ } } });
  • 71. Filters FileAPI.Image(imageFile) .filter(function (canvas, doneFn){ // processing... doneFn(); }) .get(function (err/**String*/, img/**HTMLElement*/)({ /*__*/ }) ;
  • 73. Filters + CamanJS FileAPI.Image(imageFile) .filter("hazyDays") .get(function (err/**String*/, img/**HTMLElement*/)({ /*__*/ }) ;
  • 75. WebCam navigator.getUserMedia( constraints, success, error ); — запросить разрешение на использование микрофона и/или камеры
  • 76. WebCam navigator.getUserMedia({ video: true }, function (stream){ var video = document.getElementById("webcam"); var streamSrc = URL.createObjectURL(stream); video.src = streamUrl; });
  • 77. WebCam navigator.getUserMedia({ video: true }, function (stream){ var video = document.getElementById("webcam"); var streamSrc = URL.createObjectURL(stream); video.src = streamUrl; });
  • 78. WebCam function onTakeShot(){ var video = document.getElementById("webcam"); var canvas = document.createElement("canvas"); var ctx = canvas.getContext("2d"); canvas.width = video.videoWidth; canvas.height = video.videoHeight; ctx.drawImage(video, 0, 0); }
  • 79. FileAPI.Camera var el = document.getElementById("webcam"); FileAPI.Camera.publish(el, function (cam){ });
  • 80. FileAPI.Camera var el = document.getElementById("webcam"); FileAPI.Camera.publish(el, function (cam){ FileAPI.event.on(btn, "click", function (){ var shot = cam.shot(); // FileAPI.Image instance FileAPI.upload({ url: "...", files: shot }); }); });
  • 81. jQuery.FileAPI • «Одной кнопкой» — выбрать и автоматически загрузить файл • «Ограничения» — минимальный/максимальный размер как файла, так и изображения, по ширине и высоте • «Работа с очередью» — сортировка и фильтрация очереди загрузки файлов • «Изображения» — предпросмотр, поворот и кадрирование • «Интерфейс» — гибкая и прозрачная настройка интерфейса • А также Drag’n’Drop и WebCam

Editor's Notes

  1. Добрый день, меня зовут Лебедев Константин, я работаю в компании МэйлРу, проект почта. Сегодня я поделюсь с вами нашим опытом создания open source инструмента для работы с файлами и их загрузки на сервер. По большому счету, это история из серии "а давайте все перепишем на нтмл5" и что из этого получается. Схожие проблемы испытывает любой JS разработчик при внедрении новой технологии, будь это localStorage, или IndexedDB. Везде одни и те же проблемы, это шлейф старых браузеров, разница в имплементации методов, либо их отсутствием или просто баги. Но вернемся к теме доклада. И так, FileAPI.
  2. Он позволял выбрать больше одного файла и получить информацию о них, такую как название, тип и размер, а для изображений создавать пред-просмотр.
  3. Так же у него есть возможность предварительной обработки изображений: он мог масштабировать и поворачивать. Всё это происходило на клиенте, а результат отправлялось на сервер.
  4. Однако у него был ряд недостатков. Это была flash’ка. Вся верстка, графика, бизнес-логика, и даже локализация были зашиты в нем, в результате чего решение было тяжеловесным, а внести правки мог только flash-разработчик.
  5. Но это ещё не всё. Так же у нас был второй загрузчик, для тех браузеров, которые не поддерживают flash. Это был обычный js-загрузчик, который позволял выбрать один файл и загрузить его через iframe. Вот и всё что он умел. Как вы понимаете… Вот так, появилась задача переписать наш загрузчик файлов. Тут я бы хотел пояснить, на выходе, мы хотели получить унифицированное API, которое бы работало в независимо от окружения и его можно было использовать не только в рамках проекта “Почта@Mail.ru”, но и где угодно.
  6. Для этого API были сформированы следующие требования: Во первых, необходимо сохранить текущую функциональность. Все что умел старый загрузчик, нужно перенести в новый.
  7. Во вторых, надо избавиться от недостатков. Бизнес-логика, верстка и тп, не должно содержаться в загрузчике. Только работа с файлами и как можно лучше, все остальное не его задача. В третьих, расширяемость. Если завтра окажется, что нужно получать id3 теги аудио-файла, это не должно стать сюрпризом.
  8. Первое, с чего начали, это рассмотрение возможности избавления от flash. Этому есть множество причин, например flash-блокеры или proxy, из-за которых загрузчик становился бесполезным. Так же это ещё одна технология, который имеет свои заморочки и требует поддержки.
  9. Первое, с чего начали, это рассмотрение возможности избавления от flash. Этому есть множество причин, например flash-блокеры или proxy, из-за которых загрузчик становился бесполезным. Так же это ещё одна технология, который имеет свои заморочки и требует поддержки.
  10. Первое, с чего начали, это рассмотрение возможности избавления от flash. Этому есть множество причин, например flash-блокеры или proxy, из-за которых загрузчик становился бесполезным. Так же это ещё одна технология, который имеет свои заморочки и требует поддержки.
  11. Как видите, уже более 87% браузеров поддерживают FileAPI. IE обзаведется поддержкой только с 10 версии. Но 87, это далеко не 95% и даже 90% пользователей, так что от флешь отказываться рано!
  12. Таким образом, задача свелась к созданию механизма, который совмещал бы в себе обе технологии и реализованный так, чтобы конечному разработчику было не важно как это происходит. Рассмотрим на конкретных примерах, как проходил процесс разработки.
  13. Таким образом, задача свелась к созданию механизма, который совмещал бы в себе обе технологии и реализованный так, чтобы конечному разработчику было не важно как это происходит. Рассмотрим на конкретных примерах, как проходил процесс разработки.
  14. На HTML5, это выглядит следующим образом: Получаем ссылку на инпут, далее подписываемся на событие change
  15. На HTML5, это выглядит следующим образом: Получаем ссылку на инпут, далее подписываемся на событие change. И когда оно срабатывает, получаем список файлов прямиком из него.
  16. Но что делать когда не поддерживается FileAPI, но за то поддерживается Flash? Основным принципом работы с flash, в том, что всё взаимодействие происходит непосредственно через через него, т.е. нельзя просто взять и вызвать диалог выбора файлов. Для этого, необходимо чтобы пользователь кликнул по flash, и только в этот момент открыть диалог, такова политика безопасности, диалог можно открыть только на действие пользователя.
  17. Поэтому flash объект размещается над нужным input. Сделано это очень просто, вешается обработчик события mouseover на весь документ и при наведении на input, публикуем flash-объект в его родитель, относительно которого и позиционируем с нужными размерами.
  18. При клике по флешке открывается диалог выбора файлов, пользователь там что-то выбирает и кликает «ОК». После чего, данные получает flash, которые всю очередь передает их JS, посредством вызова callback-функции. После чего JS связывает полученные данные с нужным инпутом и эмулирует событие “change”.
  19. При клике по флешке открывается диалог выбора файлов, пользователь там что-то выбирает и кликает «ОК». После чего, данные получает flash, которые всю очередь передает их JS, посредством вызова callback-функции. После чего JS связывает полученные данные с нужным инпутом и эмулирует событие “change”.
  20. Все дальнейшее взаимодействие между JS и flash, будет осуществляется через единственный доступный метод у flash, первый аргументом передается название команды, вторым объект параметров, с двумя обязательными полями: id-файла и callback. Callback будет вызван из flash, по завершению команды.
  21. После совмещения двух способов, получилось вот такое API, оно максимально приближено к нативному js, единственное различие, это способ получения файлов. Теперь мы используем метод API, тк свойство files у инпута есть только в том случае, когда браузер поддерживает HTML5/FileAPI, в случае с Flash список берется из связанных с ним данных.
  22. После совмещения двух способов, получилось вот такое API, оно максимально приближено к нативному js, единственное различие, это способ получения файлов. Теперь мы используем метод API, тк свойство files у инпута есть только в том случае, когда браузер поддерживает HTML5/FileAPI, в случае с Flash список берется из связанных с ним данных.
  23. Следующим важным шагом, является фильтрация.  Как правило, при загрузке файлов, есть ряд ограничений, таких как размер или тип. Хотя в почте и можно прикреплять любые файлы, для нас было важным получить универсальное решение, так что фильтрация необходима. В чем же её сложность?! Вся соль в том, что изначально, после получения списка файлов, мы имеем только минимальный сведения, такие как название, размер и тип. Но, что делать, когда нужно получить id3 теги или размеры изображения?
  24. Все просто, файл нужно прочесть. Для этого в существует FileReader, которые позволяет асинхронно читать файл. И на основе результата чтения, получить нужную информацию, а так как для разных типов файлов, есть свой способ её получения, мы реализовали получение только размеров изображения, как на HTML5, так и через флеш. Но, оставили возможность добавлять свои обработчики, для сбора инфы, в которых разработчик может написать свою реализацию, либо использовать готовое решение.
  25. Вот так выглядит метод фильтрации, первым аргументом передаем список файлов, вторым саму функцию фильтрации и третьим callback-который будет вызван по завершению. На выходе получаем два массива, с файлами которые подошли под условия и со всем остальными.
  26. Так же существует метод получения информации для конкретного файла.
  27. Одной из ключевых особенностей нашего flash-загрузщика, была возможность создавать предросмотр изображений. Проблема была в том, что превью было частью flash, те рисовалась в нем. В API такого быть не должно. Но как передать изображение из Flash в HTML?
  28. В этом нам поможет DataURI — это определённая стандартом схема, которая позволяет включать небольшие элементы данных в строку и использовать в качестве ссылки, в данном случае в качестве src изображения.
  29. Flash читает файл как Base64, передает результат в JS, который в начало строки добавляет схему, mime-type и метку, что данные в Base64. Теперь мы можем использовать эту строку, как src изображения.
  30. Flash читает файл как Base64, передает результат в JS, который в начало строки добавляет схему, mime-type и метку, что данные в Base64. Теперь мы можем использовать эту строку, как src изображения.
  31. Flash читает файл как Base64, передает результат в JS, который в начало строки добавляет схему, mime-type и метку, что данные в Base64. Теперь мы можем использовать эту строку, как src изображения.
  32. На хтмл5 тоже не без сюрпризов,  есть два способа получить изображение. Первый способ, это прочесть файл как DataURL, при помощи FileReader. Второй, createObjectURL — создает ссылку на файл, связанную с текущим табом. Конечно для создания пердпросмотра достаточно второго способа, но не все бразуеры его поддерживают.
  33. Так же у Оперы нет метода revokeObjectURL, который сообщает браузеру, что больше не нужно держать ссылку на файл.
  34. Класс, обладает следующими методами: кадрирование, масштабирование, поворот и preview, который автоматически кадрирует и масштабирует. Все эти методы заполняют матрицу трансформации и только при вызове метода get, она будет применена. Трансформация происходит через canvas или внутри flash, когда работает через него.
  35. Трансформация происходит через canvas или внутри flash, когда работает через него. Вот так выглядит та самая матрица,
  36. Вот так выглядит создание пердпросмотра 120х120 пикселей, вызываем метод preview, передаем требуемые размеры и вызываем метод get, на вход которого передаем callback, который будет вызван по завершению.
  37. Отдельно отмечу процесс ресайза. Если нужно получить превью 100х100, а оригинал примерно 10 МПх, а это вполне реальная ситуация, сейчас каждая мыльница кичится количеством мега-пикселей, то вы получите изображение, примерно такого качества.
  38. Как видите, ничего хорошего, сплошные искажения.
  39. Но, если сжимать в два раза, потом ещё и ещё, пока не получим требуем размер, то результат заметно лучше.
  40. Но, если сжимать в два раза, потом ещё и ещё, пока не получим требуем размер, то результат заметно лучше. Вот, сравните, разница на лицо.
  41. Но, если сжимать в два раза, потом ещё и ещё, пока не получим требуем размер, то результат заметно лучше. Вот, сравните, разница на лицо.
  42. Еще мы пробовали другие способы, такие как бикубическая интерполяция и алгоритм Ланцоша. Они конечно дают лучший результат, но очень медленные, 1.5сек против 200-300милисекунд. Также данный метод дает одинаковый результат в cavnas и flash.
  43. Последняя и основная возможность нашего API, это конечно же загрузка файлов на сервер.
  44. Вот так выглядит самый простой способ загрузки файлов.
  45. Для улучшение ситуация, добавляем в форму iframe с уникальным именем, а у формы такой же target. Теперь при сабмите, форма будет отправлена в этот ифрейм. Этот способ позволяет избавиться избавиться от обновления страницы, также работает во всех браузерах, есть возможность получить ответ от сервера, но не дает сведений о ходе загрузки.
  46. Последний способ, отправить файл на сервер, не считая flash, это XmlHttpRequest2 и FormData. Он позволяет отправить не просто тестовые данные, но и бинарные.
  47. FormData — позволяет создать набор ключ-значение. У неё есть единственный метод append, первым аргументом задаётся название POST-параметра, вторым строка или файл, также есть третий аргумент, название файла, но его пока не все поддерживают.
  48. Далее при помощи XmlHttpRequest отправляет собранные данные на сервер. Но ничего не бывает так просто. Как я уже говорил ранее, API должно уметь отправлять модифицированное изображение.
  49. Т.к. все трансформации идут через canvas, то именно его и нужно отправить на сервер и это можно сделать, при помощи трансформации canvas в blob, её можно реализовать практически во всех браузерах. Но там, где это невозможно, а это например Opera, мы загружаем cavnas ручного составления мултипарт запроса. И в этом случае, мы делаем следующее:
  50. Сначала конвертируем canvas в DataURL, а DataURLв Base64, после чего получаем BinaryString. А дальше самое интересное, руками составляем мультипарт запрос и отправляем его на сервер.
  51. Сначала конвертируем canvas в DataURL, а DataURLв Base64, после чего получаем BinaryString. А дальше самое интересное, руками составляем мультипарт запрос и отправляем его на сервер.
  52. Сначала конвертируем canvas в DataURL, а DataURLв Base64, после чего получаем BinaryString. А дальше самое интересное, руками составляем мультипарт запрос и отправляем его на сервер.
  53. Справедливости ради замечу, что данный способ используется и для тех браузеров, которые не поддерживают FormData. Т.е. При помощи FileReader читаем файл как DataURL и по такой же схеме отправляем их на сервер.
  54. На вход ему передается объект параметров: «куда заливать», «дополнительная POST-дата» и «заголовки запроса», также обработчики событий, как для слежения за ходом всей загрузки, так и отдельным файлом. Хотя HTML5 позволяет грузить все файлы сразу, стандартный механизм Flash’а нет, плюс это не очень удачная идея, пользователь может и передумать.
  55. На вход ему передается объект параметров: «куда заливать», «дополнительная POST-дата» и «заголовки запроса», также обработчики событий, как для слежения за ходом всей загрузки, так и отдельным файлом. Хотя HTML5 позволяет грузить все файлы сразу, стандартный механизм Flash’а нет, плюс это не очень удачная идея, пользователь может и передумать.
  56. Это позволяет перенести часть нагрузки по обработке изображений с сервера, на клиент.
  57. Так же функции upload возвращает xhr-образный объект, т.е. он реализует некоторые свойства и методы XmlHttpRequest, такие как
  58. Но это еще не все, на самом деле, это прокси объект. Его методы и свойства отражают состояния именно для того файла, который грузится в данный момент.
  59. 100 задач, это примерно 2 задачи в неделю. Будьте готовы отвечать на самые разнообразные вопросы, некоторые будут глупыми, другие полезными. Людей много, их задачи очень разные. Но всё это только улучшает как код библиотеки, так и её возможности.