Я достаточно давно хотел сделать расширение, которое позволяло бы просматривать данные об экспозиции фотографии, которые хранятся в EXIF. И вот, вдохновленный постом «Создание расширения для Google Chrome» решил-таки потратить на это время.
Ссылка на расширение: Exponator.
Под катом будет кратко рассказано о процессе создания, нескольких подводных камнях и задан вопрос опытным разработчикам. :-)
Сперва я озаботился поиском javascript-библиотеки, которая бы читала EXIF блок из jpeg файлов: изобретать велосипед никакого желания не было. Почти сразу я нашел необходимое на сайте Nihigoloc: http://www.nihilogic.dk/labs/exif/. В библиотеке скрипт проходит по всем изображением, скачивает их в бинарном виде, проверяет наличие EXIF-данных, парсит их и добавляет новое поле к исходному изображению. Практически то, что нужно.
Вторым шагом стало изучение документации и более подробное прочтение статьи про создание расширения. Для расширения не нужна кнопка в строке адреса, да и страница настроек на данном этапе лишняя. Недолго думая я открыл раздел Content Scripts и приступил к третьему шагу: написал, казалось бы, рабочий код, который, как ни странно, не заработал.
При этом дебаггер Хрома (я даже не ожидал, что он настолько хорош) ни на что не ругался: XMLHttpRequest отправлялся, а ответа не было. Я убил на это около часа, а потом узнал, что Content-скрипты не могут обращаться к данным вне домена страницы. А фотографии, в большинстве своем, хостятся на серверах, отличных от тех на которых отображаются.
Решением задачи оказалась фоновая страница, которая ограничивается только в манифесте расширения в разделе permissions. Если там указать http://*/, то из фоновой страницы можно будет послать запрос на любой домен. Кусок манифеста:
Но решение одной задачи влечет за собой появление следующей: как фоновой странице обмениваться данными с Content Script? Документация описывает два способа: разовый запрос и соединение, которое может жить неопределенное время. Мне нужно было отправить в фоновую страницу ссылку на изображение, загрузить ее там, а назад вернуть массив с разобранными EXIF-данными. По логике вещей мне вполне подходит разовый запрос, но я не смог разобраться в том, как он работает. А обычное соединение пошло сразу.
В результате в фоновой странице был добавлен обработчик сообщений, который получает адрес изображения, скачивает картинку, достает из нее необходимые данные и, пользуясь тем же портом, отправляет их обратно:
А в скрипте страницы создается порт, отправляется ссылка на изображение, а при получении ответного сообщения массив данных присваивается полю exifdata:
После чего из EXIF берутся диафрагма, выдержка и светочувствительность и добавляются к Title изображения:
Вопрос к залу: возможно ли получить доступ к кэшу Хрома? Кэширует ли Хром XMLHttpRequest? А то сейчас каждое изображение скачивается дважды: один раз при загрузке страницы, второй раз при получении EXIF-данных.
Ссылка на расширение: Exponator.
UPD: Некоторые картинки могут не работать. Почему-то некоторые сервера не дают их загрузить.
UPD: При желании шаблон можно изменить в настройках.
UPD: Символ * в шаблоне выводит все доступные поля EXIF.
Ссылка на расширение: Exponator.
Под катом будет кратко рассказано о процессе создания, нескольких подводных камнях и задан вопрос опытным разработчикам. :-)
Сперва я озаботился поиском javascript-библиотеки, которая бы читала EXIF блок из jpeg файлов: изобретать велосипед никакого желания не было. Почти сразу я нашел необходимое на сайте Nihigoloc: http://www.nihilogic.dk/labs/exif/. В библиотеке скрипт проходит по всем изображением, скачивает их в бинарном виде, проверяет наличие EXIF-данных, парсит их и добавляет новое поле к исходному изображению. Практически то, что нужно.
Вторым шагом стало изучение документации и более подробное прочтение статьи про создание расширения. Для расширения не нужна кнопка в строке адреса, да и страница настроек на данном этапе лишняя. Недолго думая я открыл раздел Content Scripts и приступил к третьему шагу: написал, казалось бы, рабочий код, который, как ни странно, не заработал.
При этом дебаггер Хрома (я даже не ожидал, что он настолько хорош) ни на что не ругался: XMLHttpRequest отправлялся, а ответа не было. Я убил на это около часа, а потом узнал, что Content-скрипты не могут обращаться к данным вне домена страницы. А фотографии, в большинстве своем, хостятся на серверах, отличных от тех на которых отображаются.
Решением задачи оказалась фоновая страница, которая ограничивается только в манифесте расширения в разделе permissions. Если там указать http://*/, то из фоновой страницы можно будет послать запрос на любой домен. Кусок манифеста:
"background_page": "background.html",
"permissions": [
"http://*/"
],
"content_scripts": [
{
"matches": ["http://*/*"],
"js": [ "EXIF.js", "js.js"],
"run_at": "document_start"
}
]
* This source code was highlighted with Source Code Highlighter.
Но решение одной задачи влечет за собой появление следующей: как фоновой странице обмениваться данными с Content Script? Документация описывает два способа: разовый запрос и соединение, которое может жить неопределенное время. Мне нужно было отправить в фоновую страницу ссылку на изображение, загрузить ее там, а назад вернуть массив с разобранными EXIF-данными. По логике вещей мне вполне подходит разовый запрос, но я не смог разобраться в том, как он работает. А обычное соединение пошло сразу.
В результате в фоновой странице был добавлен обработчик сообщений, который получает адрес изображения, скачивает картинку, достает из нее необходимые данные и, пользуясь тем же портом, отправляет их обратно:
chrome.extension.onConnect.addListener(function(port) {
port.onMessage.addListener(function(imgSrc) {
BinaryAjax(
imgSrc,
function(HTTP) {
var EXIF = EXIF.findEXIFinJPEG(HTTP.binaryResponse);
port.postMessage(EXIF);
}
)
});
});
* This source code was highlighted with Source Code Highlighter.
А в скрипте страницы создается порт, отправляется ссылка на изображение, а при получении ответного сообщения массив данных присваивается полю exifdata:
var port = chrome.extension.connect({name: "exif"});
port.onMessage.addListener(function(oEXIF) {
oImg.exifdata = oEXIF || {};
});
port.postMessage(oImg.src);
* This source code was highlighted with Source Code Highlighter.
После чего из EXIF берутся диафрагма, выдержка и светочувствительность и добавляются к Title изображения:
Вопрос к залу: возможно ли получить доступ к кэшу Хрома? Кэширует ли Хром XMLHttpRequest? А то сейчас каждое изображение скачивается дважды: один раз при загрузке страницы, второй раз при получении EXIF-данных.
Ссылка на расширение: Exponator.
UPD: Некоторые картинки могут не работать. Почему-то некоторые сервера не дают их загрузить.
UPD: При желании шаблон можно изменить в настройках.
UPD: Символ * в шаблоне выводит все доступные поля EXIF.