
Парсер EXIF на JavaScript

Парсер EXIF на JavaScript
JavaScript уже давно перестал быть языком, используемым только для визуальных эффектов и манипуляции контентом на web-страничках. Теперь это полноценный язык программирования, на котором написаны целые приложения, работающие как на стороне клиента, так и на стороне сервера. В качестве еще одной демонстрации практически безграничных возможностей JavaScript, предлагаю вашему вниманию полноценный парсер EXIF-данных из JPEG-файлов, написанный на чистом JavaScript и работающий исключительно в браузере, без загрузки изображений на сервер.
HTML-разметка простейшая - это обычное поле выбора файла, в котором дополнительно прописан фильтр выбора картинок, если это поддерживается браузером. Обработчик вызывается сразу после выбора файла.
Code (HTML) : Убрать нумерацию
- <div>
- <input type="file" name="uploaded_file" id="uploaded_file"
- onchange="file_selected();" accept="image/*,image/jpeg" />
- </div>
Code (JavaScript) : Убрать нумерацию
- <script type="text/javascript">
- // Обработка выбранного файла
- function file_selected() {
- try {
- var file = document.getElementById('uploaded_file').files[0];
- if (file) {
- // Предварительная проверка на JPEG
- if (/\.(jpe?g)$/i.test(file.name)) {
- // Старые версии Firefox 3.6 - 7.0
- if (typeof file.getAsBinary=='function') {
- // Содержимое файла находится в file.getAsBinary()
- // -- вызвать парсер
- }
- else if (typeof file.getAsDataURL=='function') {
- // Содержимое файла находится в file.getAsDataURL()
- // в виде закодированной base64 строки
- // -- декодировать и вызвать парсер
- }
- // Браузеры с поддержкой HTML5
- else {
- if (typeof FileReader!='undefined') {
- var reader = new FileReader();
- reader.onloadend = function(evt) {
- if (evt.target.readyState == FileReader.DONE) {
- // Данные пришли в base64
- if (evt.target.result.substr(0,5)=='data:') {
- // Содержимое файла находится в evt.target.result
- // в виде закодированной base64 строки
- // -- декодировать и вызвать парсер
- }
- // Двоичные данные
- else {
- // Содержимое файла находится в evt.target.result
- // -- вызвать парсер
- }
- }
- };
- var blob;
- if (file.slice) {
- blob = file.slice(0, file.size);
- }
- else if (file.webkitSlice) {
- blob = file.webkitSlice(0, file.size);
- }
- else if (file.mozSlice) {
- blob = file.mozSlice(0, file.size);
- }
- // Если поддерживается бинарное чтение, то использовать его
- if (typeof file.getAsBinary=='function') {
- reader.readAsBinaryString(blob);
- }
- // Использовать чтение в base64
- else {
- reader.readAsDataURL(blob);
- }
- }
- }
- }
- }
- }
- catch(e) {
- // Браузер не поддерживает работу с содержимым файлов
- }
- }
- </script>
Как вы видите в исходнике, содержимое файла не всегда сразу же доступно в бинарном виде, в некоторых случаях оно закодировано в base64. Ранее я уже приводил функцию декодирования base64 на JavaScript, она и будет использоваться для обработки данных, полученных в этом формате. На объемных картинках такая обработка неизбежно приводит к небольшой паузе, но это, к сожалению, вынужденные потери.

Пример работы парсера
Сам код парсера я в статье приводить не буду. Во-первых, он достаточно объемный, во-вторых, по своему алгоритму он мало чем отличается от парсера EXIF на PHP, описанного в этой и этой статьях. Вы можете посмотреть его в исходном тексте на демонстрационной странице.
Рабочий пример парсера EXIF на чистом JavaScript вы можете посмотреть на демонстрационной странице. Выберите изображение с вашего компьютера и вы сразу же получите информацию из EXIF: модель и производитель камеры, дату съемки, комментарии, GPS-координаты, серийный номер фотоаппарата и используемый объектив. Если каких-либо данных в файле нет, то они, естественно, показываться не будут.
Просмотров: 7354 | Комментариев: 7

Внимание! Статья опубликована больше года назад, информация могла устареть!
Комментарии
Отзывы посетителей сайта о статье
ManHunter
(31.05.2020 в 21:49):
Да, в PHP версии давно поправил, а тут что-то проморгал. Спасибо!

GreenRain
(31.05.2020 в 20:52):
Демо-пример содержит ошибку в расчете GPS-координат.
Вместо
var tmp=Math.ceil(val1/div1)+'.';
tmp+=Math.floor((val2/div2/60+val3/div3/3600)*1000000).toString();
должно быть
var tmp=val1/div1+val2/div2/60+val3/div3/3600;
Из-за ошибки скрипт вместо значения (например) 30.002953 выдает ошибочное значение 30.2953.
Ошибка проявляется, если значение количества минут val2/div2 меньше 10.
Вместо
var tmp=Math.ceil(val1/div1)+'.';
tmp+=Math.floor((val2/div2/60+val3/div3/3600)*1000000).toString();
должно быть
var tmp=val1/div1+val2/div2/60+val3/div3/3600;
Из-за ошибки скрипт вместо значения (например) 30.002953 выдает ошибочное значение 30.2953.
Ошибка проявляется, если значение количества минут val2/div2 меньше 10.

ManHunter
(01.04.2016 в 08:10):
Олег, с Java у меня ассоциируется исключительно Дюк. Но да, заменить, наверное, стоит.

Олег
(01.04.2016 в 07:47):
Чашка кофе - это Java, а не Javascript.
А за статью спасибо.
А за статью спасибо.

ManHunter
(11.08.2015 в 13:35):
Есть такое дело. Частично проблема решается чтением не всего файла, а, например, первых 200 килобайт, где с большой вероятностью может оказаться секция EXIF. Что-то типа blob = file.*Slice(0, 200000);
Для file.getAsBinary() и file.getAsDataURL() один фиг придется читать в память весь файл.
Кодировка прописана в htaccess, менять ее ради одного скрипта не хочу.

Андрей
(11.08.2015 в 13:24):
Да, вырос браузерный JavaScript. Парсер файла на JavaScript для меня удивительно, 15 лет назад так не получалось.
Жаль что демка считывает файл целиком. Со старым гремящим винчестером и jpeg-ом размером под 100 МБ факт чтения очевиден, как и с procmon.
И это...
curl -I http://www.manhunter.ru/demo/js_exif.html
Content-Type: text/html; charset=windows-1251
но
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
Жаль что демка считывает файл целиком. Со старым гремящим винчестером и jpeg-ом размером под 100 МБ факт чтения очевиден, как и с procmon.
И это...
curl -I http://www.manhunter.ru/demo/js_exif.html
Content-Type: text/html; charset=windows-1251
но
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

dros.ws
(10.08.2015 в 15:53):
А я свой чо та так и не дописал. Помню что почему-то дико тормозил а времени на решение проблемы не было. В итоге забил. Делалось то все for fun.

Добавить комментарий
Заполните форму для добавления комментария
