Converting Mapfiles to Greyscale

We use Mapserver a lot within Nautoguide and I’ve spent a significant amount of time building map files to create our base mapping. Some of these are quite complex as they traverse multiple data sets and sources, including shapefiles and PostgreSQL connections.

Our UK basemap is based upon Ordnance Survey data and looks like this in glorious colour:-

Contains OS data © Crown copyright and database right 2018

Very nice, but…sometimes we like to create our basemaps in greyscale as these offer greater contrast to features or layers we may overlay on top. I’ve previously done this by hand, laboriously trolling through my map files and replacing the colours one by one. But as I get older I get lazier and last week decided to take another path.

A bit of research into RGB colours led to the fact that a greyscale representation of a colour can be created by averaging out its RGB values.

So, if we look at RED which is:-

R=255, G=0, B=0

We can get its greyscale cousin using:-

R=(R+G+B)/3

G-=(R+G+B)/3

B=(R+G+B)/3

Simple in this case as 255/3 comes to 85 and gives us 85,85,85

Hmmmm, time to get the perl hammer out as all of the colours in my map files are HEX encoded RGB. So surely I can find them and convert them all to their greyscale equivalent. A quick hack later and we end up with this:-

use strict;

my $input_file = $ARGV[0];
my $output_file = $ARGV[1];

open(FILE, $input_file) || die ("Cannot open $input_file $!\n");

my @lines = <FILE>;
close (FILE);

my @newlines;

foreach (@lines) {

$_ =~ s/"(#[0-9A-Z]{6})"/convert_colour($1)/ge;
push (@newlines, $_);
}

open(FILE, ">$output_file") || die ("Cannot write to $output_file $!\n");
print FILE @newlines;
close(FILE);

sub convert_colour {

my $hex_colour = shift;

my $red = hex(substr $hex_colour, 1,2);
my $green = hex(substr $hex_colour, 3,2);
my $blue = hex(substr $hex_colour, 5,2);

my $x =($red + $green +$blue) / 3;
my $colour = sprintf("%02X", $x);

return '"#' . $colour . $colour . $colour .'"';

}

Not the most elegant of scripts, I’ll give you that but it works. I’m sure there are edge cases…but not in my mapfiles! Simply fire this at the command line and in no time at all you have a greyscale map:-

perl input_file.map output_file.map
Contains OS data © Crown copyright and database right 2018

Pretty much what I was after and not a lot of work to achieve. Now I know there are better algorithms for conversion to greyscale and as soon as I’ve learnt Portuguese I’ll work one of them in.

Dave Barter

CEO Nautoguide Ltd.