From c0ba2b1fb8a0128fdba50dcae7d873a45f45854e Mon Sep 17 00:00:00 2001 From: Guilhem Moulin Date: Sun, 11 Aug 2013 11:12:49 +0200 Subject: Annotate tiles. --- mkindex.pl | 125 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 116 insertions(+), 9 deletions(-) diff --git a/mkindex.pl b/mkindex.pl index 3ed4293..661655a 100755 --- a/mkindex.pl +++ b/mkindex.pl @@ -25,12 +25,16 @@ use Getopt::Long qw/:config posix_default no_ignore_case gnu_compat bundling auto_version auto_help/; use Pod::Usage; use File::Temp; +use File::Basename; +use File::Spec; +use Inline 'C'; # http://geoinformatics.aalto.fi/doc/Geo-GDAL-1.9/html/ use Geo::GDAL; use Geo::OSR; -use Inline 'C'; +# http://www.imagemagick.org/script/perl-magick.php +use Image::Magick; my %config = ( progress => Geo::GDAL->can('TermProgress_nocb') ? sub { Geo::GDAL::TermProgress_nocb(@_[0,1]) } : @@ -39,12 +43,17 @@ my %config = ( progress => Geo::GDAL->can('TermProgress_nocb') ? , rename => 's/\.[^.]+$//' , zoom => '1024x1024' , resampling => &resamplings('near') + , border => 10 + , bordercolor=> 'red' + , fontsize => 25 + , font => 'Helvetica' ); GetOptions( "q|quiet" => sub { delete $config{progress} } , "d|debug" => \$config{debug} - , "rename=s" => sub { $config{rename} = $_[1] # TODO: sanitize + , "rename=s" => sub { pod2usage(2) unless $_[1] =~ /^s(.).+\1[ixgcadlu]*$/; + $config{rename} = $_[1] } , "s|size=s" => sub { if ($_[1] =~ /^(\d*\.?\d+)(%?)$/) { $config{zoom} = $2 ? 100. / $1 : $1; @@ -57,6 +66,23 @@ GetOptions( "q|quiet" => sub { delete $config{progress} } } } , "r|resampling=s"=> sub { $config{resampling} = &resamplings($_[1]) } + , "b|border=s"=> sub { if ($_[1] =~ /^(?\d*)(?:.*)?$/) { + $config{border} = $+{b} if $+{b}; + $config{bordercolor} = $1 if $+{bc} =~ /^:(.+)/; + } + else { + pod2usage(2); + } + } + , "f|font=s" => sub { if ($_[1] =~ /^(?\d*)(?:.*)?(?:[^:]*)?$/) { + $config{fontsize} = $+{fs} if $+{fs}; + $config{fontcolor} = $1 if $+{fc} =~ /^:(.+)/; + $config{font} = $1 if $+{f} =~ /^:(.+)/; + } + else { + pod2usage(2); + } + } , "s_srs=s" => sub { $config{s_srs} = Geo::OSR::SpatialReference::->new(); $config{s_srs}->SetFromUserInput( $_[1] ) } , "t_srs=s" => sub { $config{t_srs} = Geo::OSR::SpatialReference::->new(); @@ -175,8 +201,8 @@ if ($config{zoom} =~ /^(\d+)x(\d+)$/) { my $yRatio = (0.+$lry-$uly) / ($yRes*$ySize); $config{zoom} = $xRatio < $yRatio ? $yRatio : $xRatio; - map { $_->{xRes} = $_->{transform}->[1] * $config{zoom} - ; $_->{yRes} = $_->{transform}->[5] * $config{zoom} + map { $_->{transform2}->[1] = $_->{transform}->[1] * $config{zoom} + ; $_->{transform2}->[5] = $_->{transform}->[5] * $config{zoom} } @mapset; } &debug( "Using zoom: $config{zoom}" ); @@ -203,7 +229,8 @@ foreach my $map (@mapset) { &debug ("Opening '$map->{filename}'"); my $ds = Geo::GDAL::Open($map->{filename}, 'ReadOnly') or exit 1; &expand_rgba( \$ds, $map ); - &reproject( \$ds, $map ); + my $f = &reproject( \$ds, $map ); + &annotate( $f, $map ); } @@ -313,13 +340,13 @@ sub reproject { my ($ul,$lr) = @{$map->{corners}}[0,3]; # TODO: it might be xSize that's determined from ySize - my $dst_xSize = int( ($lr->[0]-$ul->[0]) / $map->{xRes} ); + my $dst_xSize = int( ($lr->[0]-$ul->[0]) / $map->{transform2}->[1] ); my $dst_ySize = int( $dst_xSize / $config{ratio} ); my ($src_xSize, $src_ySize) = $src_ds->Size(); &debug("Reducing map from ${src_xSize}x${src_ySize} to ${dst_xSize}x${dst_ySize}."); - my $dst_filename = $index; #&tempfile(SUFFIX => '.tif'); + my $dst_filename = &tempfile(SUFFIX => '.tif'); my $dst_ds = Geo::GDAL::GetDriverByName($driver)->Create( $dst_filename , $dst_xSize , $dst_ySize @@ -328,8 +355,6 @@ sub reproject { , $driver_opts ); $dst_ds->SetProjection( $config{t_wkt} ); - $map->{transform2}->[1] = $map->{xRes}; - $map->{transform2}->[5] = $map->{yRes}; $dst_ds->SetGeoTransform( $map->{transform2} ); my $res = Geo::GDAL::ReprojectImage( $src_ds, $dst_ds, @@ -347,6 +372,88 @@ sub reproject { } +# Annotate the map (add border & caption). +sub annotate { + my $src_filename = shift; + my $map = shift; + + my $img = Image::Magick::->new(); + + $img->Read($src_filename); + my ($xSize, $ySize) = $img->Get(qw/width height/); + + &debug( "Border: $config{border}:$config{bordercolor}" ); + &debug( "Font: $config{fontsize}:". ($config{fontcolor} // $config{bordercolor}). + ":$config{font}" ); + &debug( "Text: $map->{text}"); + # To get the list of fonts: + # &debug( "Supported fonts:", map {"\t".$_} $img->QueryFont() ); + + my @draw = ( fill => 'none' + , stroke => $config{bordercolor} + , strokewidth => $config{border} + ); + my @ann = ( fill => $config{fontcolor} // $config{bordercolor} + , strokewidth => 0 + , font => $config{font} + , pointsize => $config{fontsize} + , gravity => 'Center' + , text => $map->{text} + ); + my @points; + + if ($config{t_srs}->IsSame($config{s_srs} // $map->{srs})) { + push @draw, primitive => 'rectangle'; + push @points, [ 0, 0 ], [ $xSize-1, $ySize-1 ]; + } + else { + # The projection changed. Since the map might have been rotated, + # we draw a polygon instead of a rectangle. Also, instead of + # adding the border *then* reproject we use a mask in order to + # have nice anti-aliasing and better looking fonts. + + my ($ul1,$ll1,$ur1,$lr1) = @{$map->{corners}}; + my ($rx,$ry) = @{$map->{transform2}}[1,5]; + my ($ul2,$ll2,$ur2,$lr2) = &pix2proj( $map->{transform2}, + ( [ 0, 0] + , [ 0, $ySize-1 ] + , [ $xSize-1, 0 ] + , [ $xSize-1, $ySize-1 ] + )); + push @draw, primitive => 'polygon'; + push @points, [ int(($ul1->[0]-$ul2->[0]) / $rx) + , int(($ul1->[1]-$ul2->[1]) / $ry) ] + , [ int(($ll1->[0]-$ll2->[0]) / $rx) + , int(($ll1->[1]-$ll2->[1]) / $ry) + $ySize ] + , [ int(($lr1->[0]-$lr2->[0]) / $rx) + $xSize + , int(($lr1->[1]-$lr2->[1]) / $ry) + $ySize ] + , [ int(($ur1->[0]-$ur2->[0]) / $rx) + $xSize + , int(($ur1->[1]-$ur2->[1]) / $ry) ] + ; + } + $img->Draw( @draw, points => join (' ', map {join ',', @$_} @points) ); + $img->Annotate( @ann ); + + my $dst_filename = &tempfile(SUFFIX => '.tif'); + $img->Write($dst_filename); + + # The georeference didn't change when annotating. Hence we simply + # link the former world file. + my ($src_tfw, $dst_tfw) = map { my ($name,$path) = fileparse($_, qr/\.tiff?$/); + File::Spec->catfile($path, $name.'.tfw'); + } + ($src_filename, $dst_filename); + + if (-f $src_tfw and not -f $dst_tfw) { + link $src_tfw, $dst_tfw; + &debug( "Linking worldfiles: $src_tfw -> $dst_tfw" ); + } + + undef $img; + $map->{thumbnail} = $dst_filename; +} + + __END__ __C__ -- cgit v1.2.3