#!/usr/bin/perl use CGI; use URI::Escape; use strict; use Math::Trig; my $query = CGI->new(); my $xmin = int($query->param("xmin")); my $xmax = int($query->param("xmax")); my $ymin = int($query->param("ymin")); my $ymax = int($query->param("ymax")); my $zoom = int($query->param("zoom")); my $baseurl = $query->param("baseurl"); my $scale = $query->param("scale") || 256; my $tileurl = $query->param("tileurl"); if ($tileurl =~ m!^(.*?)/(\d+)/(\d+)/(\d+)\.png!) { $xmin = $3-1; $xmax = $3+1; $ymin = $4-1; $ymax = $4+1; $baseurl = $1; $zoom = $2; $baseurl =~ s/\/(relief|trails)//g; } if ($ENV{"QUERY_STRING"} eq "") { printf("Location: bigmap.html\n\n"); exit 1; } $baseurl = "http://tah.openstreetmap.org/Tiles/tile/!z/!x/!y.png" unless defined $baseurl; # check for perl script before we do any headers if ($query->param("perl")) { makeperl(); exit 1; } print <BigMap EOF if ($query->param("form") or ($xmin<0 || $ymin<0 || $zoom<1 || $zoom>18 || $xmax>2**$zoom || $ymax>2**$zoom || $ymin>$ymax || $xmin>$xmax)) { print <bigmap Arranging OpenStreetMap Map Tiles

The bigmap service creates maps from the same tiles used for the well-known "slippy maps" (e.g. informationfreeway.org). However, it does so without Javascript or CSS. This means the resulting maps are less suitable for online browsing, but better for printing.

Please select your initial settings:
(or new! use the OpenLayers interface to select an area)



map parameters:
Zoom Level  
X Range   -
Y Range   -
all ranges in tile numbers please, not coordinates!
Tile Source  


alternatively, paste a tile URL to start:
Tile URL  

Usage:

Once you have entered coordinates above, a map will be shown consisting of the tiles requested. Note that the bigmap server never loads the tiles for you, instead it instructs your browser to load the tiles. So if you see nothing, or see garbage, then it is likely the tile server's fault, or you have entered invalid data (invalid zoom levels for example).

The map you see will be overlaid with a small control box that allows you to make corrections, e.g. enlarging, reducing, or moving the map, and zooming in or out.

Once you are satisfied with what you see, you can either hide the control box and print the page from your browser, or you can click the "Perl" link which will download a very small Perl program onto your computer that, when executed, will download all the tiles you see and compose one large PNG file from them. (This Perl script can be saved and run at a later time to capture any updates that have taken place in the mean time - no need to go back to the bigmap service.)

Perl Script Usage:
perl mkmap.pl > mymap.png

The map control box:

Adding further tilesets:

This form has only a limited number of tilesets in the dropdown box above, but you can theoretically send anything to the script - it doesn't check it.

Download bigmap.cgi source code. bigmap.cgi is written by Frederik Ramm and released into the public domain. EOF } else { # these 2 nested for loops do the actual map. for (my $y=$ymin;$y<=$ymax;$y++) { print ""; for (my $x=$xmin; $x<=$xmax; $x++) { if ($baseurl =~ /\|/) { my @layers = split(/\|/, $baseurl); my $xp = $scale * ($x-$xmin); my $yp = $scale * ($y-$ymin); my $bg = shift @layers; $bg =~ s/!z/$zoom/g; $bg =~ s/!x/$x/g; $bg =~ s/!y/$y/g; print "

\n"; print "
"; while(my $ovl = shift @layers) { $ovl =~ s/!z/$zoom/g; $ovl =~ s/!x/$x/g; $ovl =~ s/!y/$y/g; print "
\n"; print "
"; } } else { my $bg = $baseurl; $bg =~ s/!z/$zoom/g; $bg =~ s/!x/$x/g; $bg =~ s/!y/$y/g; print ""; } } print "

\n"; } # everything that follows is just for the control box! print '

'; my $widtiles = $xmax-$xmin+1; my $heitiles = $ymax-$ymin+1; my $widpix = $widtiles*256; my $heipix = $heitiles*256; my $asp="1:1"; if ($widpix>$heipix) { $asp = sprintf("%.1f:1", $widpix/$heipix); } elsif($widpix<$heipix) { $asp = sprintf("1:%.1f", $heipix/$widpix); } printf "Map is %dx%d tiles (%dx%d px) at zoom %d, aspect %s
", $widtiles,$heitiles,$widpix,$heipix,$zoom,$asp; my ($d,$o1,$a1,$d) = Project($xmin, $ymin, $zoom); my ($a2,$d,$d,$o2) = Project($xmax, $ymax, $zoom); if ($zoom>7) { printf "Bbox is %10.6f,%10.6f,%10.6f,%10.6f (l,b,r,t)
", $o1, $a2, $o2, $a1; } else { printf "Bbox is %7.2f,%7.2f,%7.2f,%7.2f (l,b,r,t)
", $o1, $a2, $o2, $a1; } print ''; print td("tl", "right", $xmin-1, $xmax, $ymin-1, $ymax, $zoom); print td("top", "center", $xmin, $xmax, $ymin-1, $ymax, $zoom); print td("tr", "left", $xmin, $xmax+1, $ymin-1, $ymax, $zoom); print ""; print td("ul", "right", $xmin-1, $xmax-1, $ymin-1, $ymax-1, $zoom); print td("up", "center", $xmin, $xmax, $ymin-1, $ymax-1, $zoom); print td("ur", "left", $xmin+1, $xmax+1, $ymin-1, $ymax-1, $zoom); print ""; print td("tl", "right", $xmin+1, $xmax, $ymin+1, $ymax, $zoom); print td("top", "center", $xmin, $xmax, $ymin+1, $ymax, $zoom); print td("tr", "left", $xmin, $xmax-1, $ymin+1, $ymax, $zoom); print ""; print td("left", "right", $xmin-1, $xmax, $ymin, $ymax, $zoom); print ""; print td("right", "left", $xmin, $xmax+1, $ymin, $ymax, $zoom); print ""; print td("left", "right", $xmin-1, $xmax-1, $ymin, $ymax, $zoom); print ""; print td("right", "left", $xmin+1, $xmax+1, $ymin, $ymax, $zoom); print ""; print td("left", "right", $xmin+1, $xmax, $ymin, $ymax, $zoom); print ""; print td("right", "left", $xmin, $xmax-1, $ymin, $ymax, $zoom); print ""; print td("bl", "right", $xmin-1, $xmax, $ymin, $ymax+1, $zoom); print td("bottom", "center", $xmin, $xmax, $ymin, $ymax+1, $zoom); print td("br", "left", $xmin, $xmax+1, $ymin, $ymax+1, $zoom); print ""; print td("dl", "right", $xmin-1, $xmax-1, $ymin+1, $ymax+1, $zoom); print td("down", "center", $xmin, $xmax, $ymin+1, $ymax+1, $zoom); print td("dr", "left", $xmin+1, $xmax+1, $ymin+1, $ymax+1, $zoom); print ""; print td("bl", "right", $xmin+1, $xmax, $ymin, $ymax-1, $zoom); print td("bottom", "center", $xmin, $xmax, $ymin, $ymax-1, $zoom); print td("br", "left", $xmin, $xmax-1, $ymin, $ymax-1, $zoom); print ""; print ""; print "
  
EXPAND SHIFT SHRINK
  
"; print ""; print td("in/double size", "left", $xmin*2,$xmax*2+1,$ymin*2,$ymax*2+1,$zoom+1); print ""; print td("in/keep size", "left", $xmin*2+($xmax-$xmin)/2,$xmax*2-($xmax-$xmin)/2,$ymin*2+($ymax-$ymin)/2,$ymax*2-($ymax-$ymin)/2,$zoom+1); print ""; print ""; print ""; print td("out/keep size", "left", $xmin/2-($xmax-$xmin)/4,$xmax/2+($xmax-$xmin)/4,$ymin/2-($ymax-$ymin)/4,$ymax/2+($ymax-$ymin)/4,$zoom-1); print ""; print td("out/halve size", "left", $xmin/2,$xmax/2,$ymin/2,$ymax/2,$zoom-1); print "
   ZOOM  
"; print ""; print td("Permalink", "left", $xmin,$xmax,$ymin,$ymax,$zoom); print ""; my $fm = td("Form", "left", $xmin,$xmax,$ymin,$ymax,$zoom); $fm =~ s/\?/?form=1&/; print $fm; print ""; my $pl = td("Perl", "left", $xmin,$xmax,$ymin,$ymax,$zoom); $pl =~ s/\?/?perl=1&/; print $pl; print ""; print td("100", "left", $xmin,$xmax,$ymin,$ymax,$zoom,256); print ""; print td("50", "left", $xmin,$xmax,$ymin,$ymax,$zoom,128); print ""; print td("25%", "left", $xmin,$xmax,$ymin,$ymax,$zoom,64); print ""; print ""; print "
    // hide this (click map to show again)
"; print "
"; } print "

"; # helper to display a table cell with a parametrized link inside sub td { my ($what, $align, $xmi, $xma, $ymi, $yma, $zm, $scl) = @_; $scl=$scale unless defined ($scl); my $r = sprintf('

%s

', $align, $xmi, $xma, $ymi, $yma, $zm, $scl, uri_escape($baseurl), $what); return $r; } # this generates the perl script that can be downloaded sub makeperl { my $widtiles = $xmax-$xmin+1; my $heitiles = $ymax-$ymin+1; my $widpix = $widtiles*256; my $heipix = $heitiles*256; my $formurl = $baseurl; $formurl .= "/$zoom/%d/%d.png"; my $bu_with_zoom = $baseurl; $bu_with_zoom =~ s/!z/$zoom/g; my $script = sprintf(<<'EOF', "http://openstreetmap.gryph.de/bigmap.cgi?xmin=$xmin&xmax=$xmax&ymin=$ymin&ymax=$ymax&zoom=$zoom&scale=$scale&baseurl=" . uri_escape($baseurl), $widpix, $heipix, $widpix, $heipix, $widtiles, $heitiles, $xmin, $ymin, $bu_with_zoom); #!/usr/bin/perl # generated from http://openstreetmap.gryph.de/bigmap.cgi/ # permalink for this map: %s # use strict; use LWP; use GD; my $img = GD::Image->new(%d, %d, 1); my $white = $img->colorAllocate(248,248,248); $img->filledRectangle(0,0,%d,%d,$white); my $ua = LWP::UserAgent->new(); $ua->env_proxy; for (my $x=0;$x<%d;$x++) { for (my $y=0;$y<%d;$y++) { my $xx = $x + %d; my $yy = $y + %d; foreach my $base(split(/\|/, "%s")) { my $url = $base; $url =~ s/!x/$xx/g; $url =~ s/!y/$yy/g; print STDERR "$url... "; my $resp = $ua->get($url); print STDERR $resp->status_line; print STDERR "\n"; next unless $resp->is_success; my $tile = GD::Image->new($resp->content); next if ($tile->width == 1); if ($base =~ /seamark/) { my $black=$tile->colorClosest(0,0,0); $tile->transparent($black); } $img->copy($tile, $x*256,$y*256,0,0,256,256); } } } binmode STDOUT; print $img->png(); EOF print "Content-type: application/octet-stream\nContent-disposition: attachment; filename=\"mkmap.pl\"\n\n$script"; } sub Project { my ($X,$Y, $Zoom) = @_; my $Unit = 1 / (2 ** $Zoom); my $relY1 = $Y * $Unit; my $relY2 = $relY1 + $Unit; # note: $LimitY = ProjectF(degrees(atan(sinh(pi)))) = log(sinh(pi)+cosh(pi)) = pi # note: degrees(atan(sinh(pi))) = 85.051128.. #my $LimitY = ProjectF(85.0511); # so stay simple and more accurate my $LimitY = pi; my $RangeY = 2 * $LimitY; $relY1 = $LimitY - $RangeY * $relY1; $relY2 = $LimitY - $RangeY * $relY2; my $Lat1 = ProjectMercToLat($relY1); my $Lat2 = ProjectMercToLat($relY2); $Unit = 360 / (2 ** $Zoom); my $Long1 = -180 + $X * $Unit; return ($Lat2, $Long1, $Lat1, $Long1 + $Unit); # S,W,N,E } sub ProjectMercToLat($){ my $MercY = shift; return rad2deg(atan(sinh($MercY))); } sub ProjectF { my $Lat = shift; $Lat = deg2rad($Lat); my $Y = log(tan($Lat) + sec($Lat)); return $Y; }