Some of the design packages I rely on use very crude GIS facilities. In fact, all they can support is a georeferenced raster as a background image, so it’s more of a rough map than GIS. It helps if these rasters are at a decent resolution, typically 1m/pixel or better.
A while back, I asked on the QGIS forum if the package could output high resolution georeferenced rasters. I received a rather terse response that no, it couldn’t (and I inferred from the tone that the poster thought that it shouldn’t, and I was wrong to want such a thing). I shelved the idea at the time.
After having to fix a lot of paths in a QGIS project file I’d moved to a new system, I noticed that all the map composer attributes are rather neatly defined in the XML file structure. Some messing around with Perl, XML::Simple and Data::Dumper::Simple, and I had a little script that would spit out an ESRI World File for the map composer raster defined in the project.
To run this, you have to create a project with just one Print Composer page, save the composed map as an image, save the project, then run the script like this:
./geoprint.pl project.qgs > image.pngw
There are some caveats:
- This probably won’t work for projects with multiple print composers
- It doesn’t quite get the scale right, but it’s within a pixel or so. I may not have corrected for image borders.
Though there’s some fairly hideous XML-mungeing in the code, what the script does is entirely trivial. If you feel you can use it, good; if you feel you can improve it, be my guest.
#!/usr/bin/perl -w
# geoprint - georef a QGIS output image by creating a world file
# one arg: qgis project file (xml)
# $Id: geoprint.pl,v 1.3 2012/04/06 03:32:01 scruss Exp $
use strict;
use XML::Simple;
use constant MM_PER_INCH => 25.4;
my $qgis = $ARGV[0];
die "$qgis must exist\n" unless ( -f $qgis );
my $q = XMLin($qgis) or die "$!\n";
my %composer = %{ $q->{Composer} };
my $image_width =
int( $composer{Composition}->{paperWidth} *
$composer{Composition}->{printResolution} /
MM_PER_INCH );
my $image_height =
int( $composer{Composition}->{paperHeight} *
$composer{Composition}->{printResolution} /
MM_PER_INCH );
# we need xpixelsize, ypixelsize, ulx and uly
my $xpixelsize =
( $composer{ComposerMap}->{Extent}->{xmax} -
$composer{ComposerMap}->{Extent}->{xmin} ) /
int( $composer{ComposerMap}->{ComposerItem}->{width} *
$composer{Composition}->{printResolution} /
MM_PER_INCH );
my $ypixelsize =
-1.0 *
( $composer{ComposerMap}->{Extent}->{ymax} -
$composer{ComposerMap}->{Extent}->{ymin} ) /
int( $composer{ComposerMap}->{ComposerItem}->{height} *
$composer{Composition}->{printResolution} /
MM_PER_INCH );
my $ulx =
$composer{ComposerMap}->{Extent}->{xmin} -
$xpixelsize *
int( $composer{ComposerMap}->{ComposerItem}->{x} *
$composer{Composition}->{printResolution} /
MM_PER_INCH ) - $xpixelsize;
my $uly =
$composer{ComposerMap}->{Extent}->{ymax} -
$ypixelsize *
int( $composer{ComposerMap}->{ComposerItem}->{y} *
$composer{Composition}->{printResolution} /
MM_PER_INCH ) - $ypixelsize;
printf( "%.12f\n%.12f\n%.12f\n%.12f\n%.12f\n%.12f\n",
$xpixelsize, 0.0, 0.0, $ypixelsize, $ulx, $uly );
# FIXME? pixel scale seems a tiny bit off - allow for border?
exit;
















