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;