Blog. Just Blog

Парсер EXIF на JavaScript

Версия для печати Добавить в Избранное Отправить на E-Mail | Категория: Web-мастеру и не только | Автор: ManHunter
Парсер EXIF на JavaScript
Парсер EXIF на JavaScript

JavaScript уже давно перестал быть языком, используемым только для визуальных эффектов и манипуляции контентом на web-страничках. Теперь это полноценный язык программирования, на котором написаны целые приложения, работающие как на стороне клиента, так и на стороне сервера. В качестве еще одной демонстрации практически безграничных возможностей JavaScript, предлагаю вашему вниманию полноценный парсер EXIF-данных из JPEG-файлов, написанный на чистом JavaScript и работающий исключительно в браузере, без загрузки изображений на сервер.

HTML-разметка простейшая - это обычное поле выбора файла, в котором дополнительно прописан фильтр выбора картинок, если это поддерживается браузером. Обработчик вызывается сразу после выбора файла.
  1. <div>
  2.     <input type="file" name="uploaded_file" id="uploaded_file"
  3.     onchange="file_selected();" accept="image/*,image/jpeg" />
  4. </div>
Самое интересное в этом примере - это получение содержимого выбранного файла. В зависимости от браузера применяется свой способ, например, старые версии Firefox могут легко получить содержимое файла через метод file.getAsBinary() или file.getAsDataURL(). Для браузеров с поддержкой HTML5 надо использовать объект FileReader, при этом тоже надо учитывать, поддерживает ли он метод readAsBinaryString() или же придется использовать только readAsDataURL(). В приведенной ниже функции я постарался учесть особенности всех браузеров.
  1. <script type="text/javascript">
  2. // Обработка выбранного файла
  3. function file_selected() {
  4.   try {
  5.     var file document.getElementById('uploaded_file').files[0];
  6.     if (file) {
  7.       // Предварительная проверка на JPEG
  8.       if (/\.(jpe?g)$/i.test(file.name)) {
  9.         // Старые версии Firefox 3.6 - 7.0
  10.         if (typeof file.getAsBinary=='function') {
  11.           // Содержимое файла находится в file.getAsBinary()
  12.           // -- вызвать парсер
  13.         }
  14.         else if (typeof file.getAsDataURL=='function') {
  15.           // Содержимое файла находится в file.getAsDataURL()
  16.           // в виде закодированной base64 строки
  17.           // -- декодировать и вызвать парсер
  18.         }
  19.         // Браузеры с поддержкой HTML5
  20.         else {
  21.           if (typeof FileReader!='undefined') {
  22.             var reader = new FileReader();
  23.  
  24.             reader.onloadend = function(evt) {
  25.               if (evt.target.readyState == FileReader.DONE) {
  26.                 // Данные пришли в base64
  27.                 if (evt.target.result.substr(0,5)=='data:') {
  28.                   // Содержимое файла находится в evt.target.result
  29.                   // в виде закодированной base64 строки
  30.                   // -- декодировать и вызвать парсер
  31.                 }
  32.                 // Двоичные данные
  33.                 else {
  34.                   // Содержимое файла находится в evt.target.result
  35.                   // -- вызвать парсер
  36.                 }
  37.               }
  38.             };
  39.  
  40.             var blob;
  41.             if (file.slice) {
  42.               blob file.slice(0file.size);
  43.             }
  44.             else if (file.webkitSlice) {
  45.               blob file.webkitSlice(0file.size);
  46.             }
  47.             else if (file.mozSlice) {
  48.               blob file.mozSlice(0file.size);
  49.             }
  50.  
  51.             // Если поддерживается бинарное чтение, то использовать его
  52.             if (typeof file.getAsBinary=='function') {
  53.               reader.readAsBinaryString(blob);
  54.             }
  55.             // Использовать чтение в base64
  56.             else {
  57.               reader.readAsDataURL(blob);
  58.             }
  59.           }
  60.         }
  61.       }
  62.     }
  63.   }
  64.   catch(e) {
  65.     // Браузер не поддерживает работу с содержимым файлов
  66.   }
  67. }
  68. </script>
Функция кроссбраузерная, поддерживаются браузеры Firefox версий 3.6+ и браузеры на движке Gecko, все современные браузеры на движке WebKit (Chrome, Opera 12+, Safari 6+, Vivaldi), Internet Explorer 10, последняя Opera на движке Presto версий 11. Не поддерживается Internet Explorer 9 версии и ниже, Safari версии 5 и ниже, а также браузер с красной дыркой ниже версии 11. Я не проверял скрипт на новом браузере Edge, но подозреваю, что и там должно все работать без каких-либо проблем.

Как вы видите в исходнике, содержимое файла не всегда сразу же доступно в бинарном виде, в некоторых случаях оно закодировано в 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.
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" />
dros.ws (10.08.2015 в 15:53):
А я свой чо та так и не дописал. Помню что почему-то дико тормозил а времени на решение проблемы не было. В итоге забил. Делалось то все for fun.

Добавить комментарий

Заполните форму для добавления комментария
Имя*:
Текст комментария (не более 2000 символов)*:

*Все поля обязательны для заполнения.
Комментарии, содержащие рекламу, ненормативную лексику, оскорбления и т.п., а также флуд и сообщения не по теме, будут удаляться. Нарушителям может быть заблокирован доступ к сайту.
Наверх
Powered by PCL's Speckled Band Engine 0.2 RC3
© ManHunter / PCL, 2008-2025
При использовании материалов ссылка на сайт обязательна
Время генерации: 0.07 сек. / MySQL: 2 (0.0063 сек.) / Память: 4.5 Mb
Наверх