Kentaro Kuribayashi's blog

Software Engineering, Management, Books, and Daily Journal.

「Exif JSONサービス」から Exif 情報を引っ張ってきて表示したい

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;
    }
})();