aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xmaketiles/packtiles155
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");