ITゲリラ戦士にアパッチはいらない Pt. 2 <TMSグリッドを表示するTMS サーバをつくるまで>

TMSのタイルファイル名を表示するTMSサーバを実装しました。

こういうものが表示されるものを作りました

グリッドが、 TMS サーバが出力しているものです。

実装

タイル画像は RMagick で作ります。Rack には RMagick::Image#to_blob の出力を渡してあげるだけでOKです。

require 'stringio'
require 'rubygems'
require 'rmagick'

use Rack::CommonLogger

map '/' do
  run proc {|env|
    [200, {'Content-Type' => 'text/html'}, StringIO.new(<<-EOS
<?xml version="1.0" encoding="UTF-8"?>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<script src="http://openlayers.org/dev/OpenLayers.js"></script>
<script>
var map;

function osm_getTileURL(bounds) {
  var res = this.map.getResolution();
  var x = Math.round((bounds.left - this.maxExtent.left) / 
                     (res * this.tileSize.w));
  var y = Math.round((this.maxExtent.top - bounds.top) / 
                     (res * this.tileSize.h));
  var z = this.map.getZoom();
  var limit = Math.pow(2, z);

  if (y < 0 || y >= limit) {
    return OpenLayers.Util.getImagesLocation() + "404.png";
  } else {
    x = ((x % limit) + limit) % limit;
    return this.url + z + "/" + x + "/" + y + "." + this.type;
  }
}

function init() {
  map = new OpenLayers.Map('map', {
    controls:[
      new OpenLayers.Control.Navigation(),
      new OpenLayers.Control.PanZoomBar(),
      new OpenLayers.Control.LayerSwitcher(),
      new OpenLayers.Control.Permalink(),
      new OpenLayers.Control.MousePosition(),
      new OpenLayers.Control.Attribution()],
    maxExtent: 
      new OpenLayers.Bounds(-20037508.34,-20037508.34,20037508.34,20037508.34),
    numZoomLevels:18,
    maxResolution: 156543.0399,
    units: 'm',
    projection: new OpenLayers.Projection("EPSG:900913"),
    displayProjection: new OpenLayers.Projection("EPSG:4326")});
  var tah = new OpenLayers.Layer.TMS(
    'OSM Tiles@Home', 
    'http://tah.openstreetmap.org/Tiles/tile/',
    {type: 'png', getURL: osm_getTileURL,
     displayOutsideMaxExtent: true,
     attribution: 'map: OpenStreetMap Tiles@Home'});
  var ltm = new OpenLayers.Layer.TMS(
    'TMS Grid by TMS',
    'http://' + window.location.host + '/tms/',
    {type: 'png', getURL: osm_getTileURL,
     displayOutsideMaxExtent: true,
     isBaseLayer: false,
     attribution: 'Local TMS'});
  map.addLayers([ltm, tah]);
  if(!map.getCenter()) {
    map.setCenter(new OpenLayers.LonLat(9.69873, 52.38736).transform(
      new OpenLayers.Projection("EPSG:4326"),
      new OpenLayers.Projection("EPSG:900913")), 15);
  }
}
</script>
</head>
<body onload="init()">
<div id="map"></div>
</body>
</html>
    EOS
    )]
  }
end

map '/tms' do
  run proc {|env|
    img = Magick::Image.new(256, 256) {
      self.format = 'PNG'
    }
    img.opacity = 65535
    draw = Magick::Draw.new
    draw.pointsize = 16
    draw.gravity = Magick::CenterGravity
    draw.annotate(img, 0, 0, 2, 2, env['PATH_INFO'])
    draw.stroke('gray')
    draw.stroke_width = 1
    draw.fill_opacity(0)
    draw.stroke_opacity(0.5)
    draw.polyline(0, 0, 255, 0, 255, 255, 0, 255, 0, 0)
    draw.draw(img)
    [200, {'Content-Type' => 'image/png'}, img.to_blob]
  }
end