diff options
-rwxr-xr-x | maketiles/packtiles | 155 |
1 files changed, 155 insertions, 0 deletions
diff --git a/maketiles/packtiles b/maketiles/packtiles new file mode 100755 index 000000000..1c209dc0e --- /dev/null +++ b/maketiles/packtiles @@ -0,0 +1,155 @@ +#!/usr/bin/perl -w +# +# packtiles: +# Pack a tree of tiles etc. as generated by 10kfull etc. into the more efficient +# packed format which is read by the tile server. +# +# Copyright (c) 2006 UK Citizens Online Democracy. All rights reserved. +# Email: chris@mysociety.org; WWW: http://www.mysociety.org/ +# + +my $rcsid = ''; $rcsid .= '$Id: packtiles,v 1.1 2006-09-20 11:25:09 chris Exp $'; + +use strict; + +use CDB_File; +use Errno; +use File::Slurp; +use File::stat; +use IO::Dir; +use IO::File; + +use constant TILEID_LEN => 20; +use constant BLOCKING => 14; + +sub debug (@) { + print STDERR @_; +} + +sub pack_tile_dir ($$) { + my ($indir, $outdir) = @_; + +} + +# new_index_block +# +sub new_index_block () { + # Initially all tiles are null so all bits are set. + my $bitmaplen = int((BLOCKING * BLOCKING + 8) / 8); + my $buf = "\xff" x $bitmaplen; + $buf .= "\00" x (BLOCKING * BLOCKING * TILEID_LEN); +} + +# add_tile_to_index_block BLOCK X Y ID +# +sub add_tile_to_index_block ($$$$) { + my $x = $_[1]; + my $y = $_[2]; + my $id = $_[3]; + + # clear the nullness bit. + my $off = $x + $y * BLOCKING; + my $b = unpack('C', substr($_[0], $off >> 3, 1)); + $b &= ~(1 << ($off & 7)); + substr($_[0], $off >> 3, 1) = pack('C', $b); + + # stick the tile itself in. + my $bitmaplen = int((BLOCKING * BLOCKING + 8) / 8); + substr($_[0], $bitmaplen + $off * TILEID_LEN, TILEID_LEN) = $id; +} + +die "arguments are input (unpacked) tile directory, and output (packed)\n" + . "tileset directories\n" + if (@ARGV != 2); + +my ($inputdir, $outputdir) = @ARGV; +$inputdir =~ s#/$##; +$outputdir =~ s#/$##; +die "$inputdir: not a directory" if (!-d $inputdir); +die "$outputdir: not a directory" if (!-d $outputdir); + +# first make the index of tile locations to IDs. +my %index; +debug("reading index of tile locations to IDs...\n"); +my $f = new IO::File("$inputdir/index", O_RDONLY); +my $len = stat($f)->size(); +my $n = 0; +while (defined(my $line = $f->getline())) { + debug("\rreading index: ", $f->tell(), "/$len bytes") + if (0 == ($n % 100)); + ++$n; + + next if ($line =~ /^#/); + + chomp($line); + my ($x, $y, $hash) = split(/ /, $line); + my $id = pack('H*', $hash); + + my $x2 = int($x / BLOCKING); + my $y2 = int($y / BLOCKING); + + $index{"$x2,$y2"} ||= new_index_block(); + add_tile_to_index_block( + $index{"$x2,$y2"}, + $x % BLOCKING, $y % BLOCKING, + $id); +} +debug("\rreading index: $len/$len bytes\n"); + +die "$inputdir/index: $!" if ($f->error()); +$f->close(); + +debug("writing index blocks to index.cdb... "); +my $C = new CDB_File("$outputdir/index.cdb", "$outputdir/index.new"); +foreach (keys(%index)) { + $C->insert($_, $index{$_}); +} +debug("done\n"); +debug("finalising index.cdb... "); +$C->finish(); +debug("done\n"); + +debug("packing individual tile directories...\n"); +my $n = 0; +for (my $u = 0; $u < 4096; ++$u) { + my $subpath = sprintf('%x/%x/%x', $u & 0xf, ($u >> 4) & 0xf, $u >> 8); + + next unless (-d "$inputdir/$subpath"); + + # Ensure the path exists. + foreach my $p (qw(1 3 5)) { + my $d = "$outputdir/" . substr($subpath, 0, $p); + die "$d: mkdir: $!" if (!mkdir($d) && !$!{EEXIST}); + } + + my $in = "$inputdir/$subpath"; + my $out = "$outputdir/$subpath"; + + my $f = new IO::File("$out/tiles", O_WRONLY | O_CREAT | O_TRUNC, 0644) + or die "$out/tiles: open: $!"; + $C = new CDB_File("$out/tiles.cdb", "$out/tiles.tmp"); + my $d = new IO::Dir($in) or die "$in: $!"; + while (my $name = $d->read()) { + next unless ($name =~ /^([0-9a-f]+)\.png$/); + my $id = pack('H*', $1); + my $buf = read_file("$in/$name") or die "$in/$name: $!"; + + die "$in/$name: length of file read by File::Slurp did not match stat" + unless (stat("$in/$name")->size() == length($buf)); + + my $rec = sprintf('%x:%x', $f->tell(), length($buf)); + $C->insert($id, $rec); + + die "$out/tiles: write: $!" if ($len != $f->write($buf, $len)); + + ++$n; + } + + $f->close(); + $C->finish(); + + debug("\rpacking tiles: $u/4096"); +} + +debug("\rpacking tiles: 4096/4096\n"); +debug("packed $n tiles total\n"); |