Exif JSONサービス – Ogawa::Memoranda」なんつって、画像の URL を指定すると、その画像の Exif 情報を返すなんてなステキ API が公開されたので、ぐりもんでいじってみたりしました。……が、以下のような感じで作ってみたのだけど、なんかマウスをガシガシ動かしまくって、Exif情報を出したり消したりしまくってると、Firefoxが固まる……。なんでー。
まぁ以下、メモ掲載。

// ==UserScript==
// @name          Show Exif
// @namespace     http://kentarok.org/
// @include       *
// ==/UserScript==
//
// ==Acknowledgments==
//
// This script appears thanks to:
//
// Exif JSON API - Ogawa::Memoranda
// http://as-is.net/blog/archives/001206.html
//
// ==Author & Copyright==
//
// Copyright (C) 2007 by Kentaro Kuribayashi
// This script is distributed under the MIT License
//
(function(){
var popupId  = 'GM-Show-Exif';
var callback = 'GM_showExif';
var jsonp    = new JSONP;
unsafeWindow.GM_showExif = showExif;
document.body.appendChild($N('div', {
id   : popupId,
style: {
color          : '#333333',
border         : 'solid 1px #333333',
backgroundColor: '#ffffb2',
padding        : '1em',
display        : 'none',
position       : 'absolute',
},
}));
$A(document.images).forEach(function (image) {
var jsonpURI = ['http://as-is.net/exif/json?url=', image.src, '&callback=', callback].join('');
image.addEventListener('mouseover', function (event) {
jsonp.executeRequest(jsonpURI);
$(popupId).style.display = 'block';
$(popupId).style.top     = (event.pageY + 10) + 'px';
$(popupId).style.left    = (event.pageX + 10) + 'px';
}, false);
image.addEventListener('mouseout', function () {
jsonp.removeRequest(jsonpURI);
$(popupId).style.display = 'none';
}, false);
});
function showExif (exif) {
var lines = [];
for (var p in exif) {
lines.push(['<strong>', p, ':</strong> ', exif[p], '<br>'].join(''));
}
$(popupId).innerHTML = lines.join("\n");
};
function JSONP () {
this.requests = {};
this.head = document.getElementsByTagName('head')[0];
this.executeRequest = function (jsonpURI) {
var script         = document.createElement('script');
script.type    = 'text/javascript';
script.charset = 'utf-8';
script.src     = jsonpURI;
this.head.appendChild(script);
this.requests[jsonpURI] = script;
};
this.removeRequest = function (jsonpURI) {
this.head.removeChild(this.requests[jsonpURI]);
delete this.requests[jsonpURI];
};
}
function $ (id) {
return document.getElementById(id);
}
function $A (arg) {
var array = [];
for (var i = 0, l = arg.length; i < l; i++) {
array.push(arg[i]);
}
return array;
}
function $N (tag, props, children) {
var element = document.createElement(tag);
for (var k in props) {
var v = props[k];
if (k == 'style') {
for (var p in v) {
element.style[p] = v[p];
}
}
else if (k == 'event') {
v.forEach(function (e) {
element.addEventListener(e.name, e.callback, e.flag);
});
}
else if (k == 'class') {
element.className = v;
}
else {
element.setAttribute(k, v);
}
}
if (children instanceof Array) {
children.forEach(function (child) {
if ((typeof(child) == 'string' || child instanceof String)) {
element.appendChild(document.createTextNode(child));
}
else {
element.appendChild(child);
}
});
}
return element;
}
})();