世界の測量

Sibling of "Relevant, Timely, and Accurate, " but much lighter and shorter ※自らの所属する組織の見解を示すものでない

電子国土タイル画像をクライアントサイドでグレースケール化

SotM USA のサイトで使用されていた modLayer の技術を電子国土タイルに適用して、電子国土タイルをクライアント側でグレースケール化する方法を確かめてみた:
http://www.handygeospatial.info/2012/11/08/
cyberjapandata.gsi.go.jp のデータを www.handygeospatial.info でクロスオリジン処理できるように、http://blog.hidekiy.com/2010/10/xhr-xhr-lv2proxy.html で紹介されている「レスポンスヘッダにAccess-Control-Allow-Origin: * (すべて許可)を追加して返してくれるProxy」である http://allow-any-origin.appspot.com/ を使用させていただいた。

注釈

モダンでないブラウザではグレースケール化されず、カラーのまま表示されるかもしれないとのこと。

気づき

通常の mapbox.js では、canvas が tainted になってグレースケール化されない。
http://stateofthemap.us/js/mapbox.min-dirty.js に何か秘密がある。これをロードするようにしたところ、動くようになった。あとで原因を調べる。

主要なコード

var filter = function(data) {
  var skip = 1;
  var val;
  for (var x = 0; x < 256; x += skip) {
    for (var y = 0; y < 256; y += skip) {
      if (data[4 * ((y * 256) + x) + 0] == 181 &&
        data[4 * ((y * 256) + x) + 1] == 208 &&
        data[4 * ((y * 256) + x) + 2] == 208) {
        val = [255, 255, 255];
      } else {
        if (true) val = [
          Math.pow(data[4 * ((y * 256) + x) + 1] / 255, 0.5) * 255,
          Math.pow(data[4 * ((y * 256) + x) + 1] / 255, 0.5) * 255,
          Math.pow(data[4 * ((y * 256) + x) + 1] / 255, 0.5) * 255];
        if (false) val = [
          data[4 * ((y * 256) + x) + 1] - 100 + 140,
          data[4 * ((y * 256) + x) + 1] - 100 + 35,
          data[4 * ((y * 256) + x) + 1] - 100 + 85];
       }
      for (var s = 0; s < skip; s++) {
        for (var s0 = 0; s0 < skip; s0++) {
          var r = (Math.random() > 2) ? (Math.random() * 20) : 0;
          var n = data[4 * (((y + s0) * 256) + x + s) + 0];
          data[4 * (((y + s0) * 256) + x + s) + 0] = (val[0]) + r;
          data[4 * (((y + s0) * 256) + x + s) + 1] = (val[1]) + r;
          data[4 * (((y + s0) * 256) + x + s) + 2] = (val[2]) + r;
        }
      }
    }
  }
}

var gsi = new modLayer(new MM.MapProvider(function(coord) {
  var did = [null, null, null, null, null, 
             'RELIEF', 'RELIEF', 'RELIEF', 'RELIEF',
             'BAFD1000K', 'BAFD1000K', 'BAFD1000K',
             'BAFD200K', 'BAFD200K', 'BAFD200K',
             'DJBMO', 'DJBMO', 'DJBMO', 'FGD'][coord.zoom];
  var tid = ('0000000' + coord.column).slice(-7) + 
            ('0000000' + coord.row).slice(-7);
  var url = 'http://allow-any-origin.appspot.com/' + 
    'http://cyberjapandata.gsi.go.jp/sqras/all/' + did + 
    '/latest/' + coord.zoom + 
    '/' + tid.charAt(0) + tid.charAt(7) +
    '/' + tid.charAt(1) + tid.charAt(8) +
    '/' + tid.charAt(2) + tid.charAt(9) +
    '/' + tid.charAt(3) + tid.charAt(10) +
    '/' + tid.charAt(4) + tid.charAt(11) +
    '/' + tid.charAt(5) + tid.charAt(12) +
    '/' + tid + (coord.zoom > 14 ? '.jpg' : '.png');
  return url;
}), filter);

map = mapbox.map('map', gsi);
map.tileSize = {x: 255, y: 255}
map.centerzoom({lat: 35.68146889341397, lon: 139.76604980197698}, 16);

ブラウザサイドで空中写真画像処理ができそうな気がしてきた。