Unix command-line tile cutter for Google Maps

When I released my new Toronto transit map I promised to release some of the tools I used to create it. Possibly the most useful tool I created is my command-line tile cutter. True, there are other image tilers, such as a Photoshop script and a web-based tool which uses Google Maps. I don’t have Photoshop and find it slow, and the web-based tool is difficult to use even with small files, so I created my own tile cutter.

My image tiler uses Free Software, is released under the GPL, and has the following features:

The tiler requires ImageMagick and advpng or pngcrush for PNG compression. (I recommend advpng as it is faster and compresses smaller in most situations.) Tiled image size is restricted only by disk space and ImageMagick limitations.

To use the tile cutter, one need only specify the image being tiled, the Google tile coordinates of the top-left tile, the zoom level for which those coordinates are valid and the zoom level the tile represents. For example, suppose we have three images (img15.png, img16.png and img17.png) for zoom levels 15 through 17 (in version 2 zoom levels), respectively. The top-left corner of the image at level 15 is 1812,1924. You would then run the following commands to generate the tiles:

% googletilecutter -o 15 -t 1812,1924 -z 15 img15.png
% googletilecutter -o 15 -t 1812,1924 -z 16 img16.png
% googletilecutter -o 15 -t 1812,1924 -z 17 img17.png

Note that the only options which need to be changed from image to image are the zoom level of the image and the image itself. Compression and discarding of empty tiles is performed automatically. For more command-line options execute the script with the -h option.

Download the Unix command-line tile cutter for Google Maps. If you have any problems or experience any unexpected behaviour, please leave a comment below.

  1. Eli

    May 9, 2007 at 11:16 pm

    Hi Ian,

    I’m interested in using your sh script that you wrote, but an error keeps coming up when trying to initiate the program. Here’s the output of the command when trying to use it.

    eli% tilecutter -o 15 -t 772,571 -z 15 ds9.tif
    csh: .: Command not found.
    /usr/bin/tilecutter: line 111: [: too many arguments
    csh: .: Command not found.
    Using pngcrush for compression.
    Padding image …
    identify: ds9.tif: unknown field with tag 34665 (0x8769) encountered..
    convert: ds9.tif: unknown field with tag 34665 (0x8769) encountered..
    Generating tiles …
    Renumbering and compressing tiles …
    identify: unable to open file `/tmp/map-XXXXXX.OViCcJKb-tile-0′: No such file or directory.
    identify: unable to open file `/tmp/map-XXXXXX.OViCcJKb-tile-1′: No such file or directory.
    identify: unable to open file `/tmp/map-XXXXXX.OViCcJKb-tile-2′: No such file or directory.
    identify: unable to open file `/tmp/map-XXXXXX.OViCcJKb-tile-3′: No such file or directory.
    identify: unable to open file `/tmp/map-XXXXXX.OViCcJKb-tile-4′: No such file or directory.
    identify: unable to open file `/tmp/map-XXXXXX.OViCcJKb-tile-5′: No such file or directory.
    identify: unable to open file `/tmp/map-XXXXXX.OViCcJKb-tile-6′: No such file or directory.
    identify: unable to open file `/tmp/map-XXXXXX.OViCcJKb-tile-7′: No such file or directory.
    identify: unable to open file `/tmp/map-XXXXXX.OViCcJKb-tile-8′: No such file or directory.
    identify: unable to open file `/tmp/map-XXXXXX.OViCcJKb-tile-9′: No such file or directory.
    identify: unable to open file `/tmp/map-XXXXXX.OViCcJKb-tile-10′: No such file or directory.
    identify: unable to open file `/tmp/map-XXXXXX.OViCcJKb-tile-11′: No such file or directory.

    Any clues as to where I should start looking into?

    Thanks for your consideration and writing such a program.

    Cheers,

    Eli

  2. Ian Stevens

    May 10, 2007 at 7:54 pm

    Hm, there are a number of things wrong here. This shouldn’t be running under csh. Find out where your bash shell is and change the first line of the script to reflect that. It might be /usr/bin/bash, not /bin/bash.

    It also looks like identify can’t parse your .tif file and is failing to pad it. Not sure why.

  3. Peter

    October 17, 2007 at 7:11 am

    What do I need to do to get this up and running. Do you have a easy cant go wrong guide to how to cut up tiles. So far all the examples online are sparse to say the least and there is no easy all you need to do to create your own tiles is…

    1. get an image of the world like this one… i.e.
    2. using the following …..
    3. running the script under linux you will need to make sure you install X and Y via apt-get, yum or whatever package manager you use…

    At the moment when I run your script i get the following:

    Advpng or pngcrush not found. Using no PNG compression.
    Padding image …
    ./googletilecutter.sh: line 140: identify: command not found
    ./googletilecutter.sh: line 152: convert: command not found
    Generating tiles …
    ./googletilecutter.sh: line 161: convert: command not found
    Renumbering and compressing tiles …
    ls: /tmp/map-HUzlU1-tile*: No such file or directory

    Any info would be appreciated!

    Thanks

  4. Ian Stevens

    October 17, 2007 at 2:12 pm

    Hi Peter. My tile cutter requires you to install ImageMagick, which you do not have installed. If you’re under a Debian variant, running apt-get imagemagick should solve the problem.

    Admittedly, a more suitable error message should be output, and I’ve created a ticket reflecting this. Unfortunately, the script won’t auto-install missing packages.

    I hope this helps. If you’re still having problems, let me know.

  5. Bo Bjerregaard

    May 2, 2008 at 8:01 am

    Hi Ian,

    I’ve been using googletilecutter, and so far I’m pretty happy with the results, great work!

    But at the moment I’m running into some issues cutting tiles so I can zoom in on them.

    I have a source-map, which has coords 34623, 20350 @ zoom-level 16, that I’ve used googletilecutter to cut up into 9 tiles. I want to be able to zoom further in on the map, how would I be able to do this? I’ve tried cutting up the resulting tiles into more tiles to get another zoomlevel, but it just doesn’t work…

    I hope you can help me out :)

    ~Bo

  6. Martoosh

    June 6, 2008 at 3:56 pm

    Hi Ian,

    I’m looking for a tool that will allow me to cut out a section from a map online, from google maps for instance.

    Is this the function of the Unix command-line tile cutter? Forgive my ignorance, I am a social worker (not a computer scientist) and am not literate with tools – however I’m trying to create a document and such a tool would be useful.

    Thank you, best,
    Marta

  7. Ian Stevens

    June 7, 2008 at 1:06 pm

    Sorry Martoosh, this utility just cuts an existing image into tiles suitable for Google Maps. It does not do the reverse. There are apps that do this. Search for “google maps tile stitcher” or something similar.

  8. P.R.

    September 13, 2008 at 12:52 am

    Ive created a large, full-globe projection using a program called GrADS, and the image lat/lon values range from -180 to +180 longitude, +90 to -90 latitude.

    However, Ive noticed that google’s map progjection ranges from about -85 to +85 latitude (it doesnt go all the way to 90 degrees), and also that the change in latitude across the center tiles is not uniform (i.e., at zoom level 2, tile 2 goes from 0 to about 66 degrees, instead of going to 45 degrees, because 180degrees/4 tiles should equal a tile height of 45 degrees, guessing this is because of the mercator distortion?).

    Anyway, Im wondering if your tiler takes care of this stuff, or would my image need to already be compatible with google’s projection? (so, would my image already have to start & end at 85 degrees latitude instead of 90 degrees, and would the center latitudes need to already be “distorted”, in mercator???)…please help…

  9. DamageInc

    September 22, 2008 at 7:10 am

    There is a small bug in this when you give it an image with power-of-two dimensions where it will create one more tile than required (since it always rounds up).

    I changed:

    width=$((`echo $dim | sed -e “s/x.*//”`+$padX))
    tileWidth=$(($width / 256 + 1))
    height=$((`echo $dim | sed -e “s/.*x//”`+$padY))
    tileHeight=$(($height / 256 + 1))

    to:

    width=$((`echo $dim | sed -e “s/x.*//”`+$padX))
    tileWidth=$((($width – 1) / 256 + 1))
    height=$((`echo $dim | sed -e “s/.*x//”`+$padY))
    tileHeight=$((($height – 1) / 256 + 1))

    and it seems to work fine.

  10. Patrick

    October 2, 2008 at 3:38 pm

    Excellent little tool.

    I found that I had to rename the file with no extension to get a .jpg to be tiled on a mac OSX-10.5

  11. Robert

    January 14, 2009 at 1:05 am

    ImageMagic has many versions to interface to various languages (Perl, tcl, ruby, …). But, I don’t see one for bash, or shell scripting at all. Which one should I get?

    Thanks,
    Robert

  12. Ian Stevens

    January 15, 2009 at 10:56 pm

    Hi Robert. When using BASH in scripts, I prefer to interface with ImageMagick using the command-line scripts, as I did with my tile-cutter. The command-line client is great in that you can apply many effects and transformations in a single line.

  13. Robert

    January 16, 2009 at 12:38 am

    OK, It works! I have a minimal linux installation, so ImageMagic took some tweaking to install. But it works at the command line – and I totally agree, command-line’s the best way to go. Thanks for sharing this useful scritp!

    Robert

  14. Ray

    February 15, 2009 at 7:35 am

    Hi Ian,
    I’m still seeing this error. I should have everything I need installed.

    bash-3.2$ ./googletilecutter-0.10.sh -o 15 -t 1812,1924 -z 15 image.jpg
    Using advpng for compression.
    Padding image …
    Generating tiles …
    Renumbering and compressing tiles …
    ls: /var/folders/RP/RPcPqaqMGsahjBfs7JB0l+0Nfzw/-Tmp-//map-XXXXXX.NtN1jQ0D-tile*: No such file or directory

    Any ideas?

  15. Austin

    March 25, 2009 at 1:39 am

    @Ray

    It seems that one or more of the components in the script have changed.

    If you’re still interested in this script, here is how you fix it:
    line 149: Remove the -t (This will put the temporary files into your current directory, but it seems the the -t option produces an unexpected output name)
    line 206: Change ‘mktemp’ to ‘mktemp crushed-XXXXXX’

    Again, this makes all of the temporary files in your local directory, but the script cleans up afterwards.

  16. Mark

    October 8, 2009 at 4:48 am

    FYI,

    I encountered the same temp file related error as Ray on OS/X 10.5.8. The fix Austin posted worked.

    Very helpful script Ian, thanks.

  17. Jonathan

    March 25, 2010 at 3:20 pm

    I have this problem when i executed googletilecutter from perl or shell doesn’t any problem but if i executed the same from C, ìt shows me this error

    which: no advpng in ((null))
    which: no pngcrush in ((null))
    Advpng or pngcrush not found. Using no PNG compression.
    Padding image …
    Generating tiles …
    Renumbering and compressing tiles …
    Compressing gfsd1calsfct0z4x3y6.png … ./googletilecutter-0.10.sh: line 202: [: ==: unary operator expected
    ./googletilecutter-0.10.sh: line 205: [: ==: unary operator expected 0%
    Compressing gfsd1calsfct0z4x4y6.png … ./googletilecutter-0.10.sh: line 202: [: ==: unary operator expected
    ./googletilecutter-0.10.sh: line 205: [: ==: unary operator expected 0%
    Compressing gfsd1calsfct0z4x5y6.png … 0%
    ./googletilecutter-0.10.sh: line 202: [: ==: unary operator expected
    ./googletilecutter-0.10.sh: line 205: [: ==: unary operator expected

    Any ideas?

    Thanks Ian

  18. Ian Stevens

    March 27, 2010 at 8:27 pm

    You don’t have either pngcrush or advpng installed. There’s a bug in the code. On line 125, where it says:

    compress=””

    Replace that with

    compress=”none”

    Let me know if that works for you.

  19. Kevin

    June 15, 2010 at 4:28 pm

    I may be missing something simple or basic, but I don’t see what units the coordinates are assumed to be in. If they’re Lat/Lngs, how does your example of “1812,1924” convert in comment 20?

    Anyway, thanks for offering up this script for free! It’s much appreciated! :)

  20. Kevin

    June 21, 2010 at 3:02 pm

    Hi Ian, thanks for replying so quickly to my question last time. I’m still having trouble getting everything working, but much of that doesn’t have much to do with you.

    I guess I’m still having trouble understanding the relationship between the “-z” and “-o” options in your script. Wouldn’t they always be at the same zoom level? Or, when would this not be the case? Maybe my misunderstanding is causing the tilecutter to cut the tiles into the same size with the same resolution/content, no matter the parameters.

    Thanks in advance!

  21. Ian Stevens

    June 21, 2010 at 4:45 pm

    The -o and -z options are unrelated; it’s -o and -t that are related. The -o option is the zoom level at which the coordinates provided by -t were measured.

    Suppose you have your layer as a single image. You could create a small-ish version of it and use http://open.atlas.free.fr/GMapsTransparenciesImgOver.php to position it over a map. (There are likely other maps that perform this task better, but this is the one I link to above.) The numbers for -t are the values in the X and Y boxes and the value for -o is the value of the Z box. Knowing the coordinates of the top-left corner, the script can now tile your layer for any zoom level, designated by -z.

  22. allankliu

    June 22, 2010 at 7:54 pm

    Good script, I am going to build my own image distribution system based upon GIS map framework. I am also trying to implement it in Bash shell, rather than Python. You script gives much information. There are some differences between your implementation and my daily work.

    1) I use Lat/Lng/Zoom rather than x/y/z, which is calculated by Python or bc.
    2) I would rather to crop off picture if it just a little bigger than 256 pix.

    Thanks for your code.

  23. Alex

    August 23, 2010 at 5:59 pm

    hello,
    i’ve used your tool to build a middle-earth map, extremely useful! thanks!

    is there any way to specify a background color if the tile is not a multiple of 256?

  24. Ian Stevens

    August 25, 2010 at 11:47 am

    Hi Alex. There is no way to currently specify the background colour. I assume that all maps will be overlays and would require some level of transparency. What you could do is add a layer underneath the map tile layer, which makes use of a single tile image of solid colour.

  25. Ian Stevens

    September 7, 2010 at 8:06 pm

    Sorry, Mo, it will not automatically scale your tiles for different zoom levels. You will have to generate large images, one per zoom level, and execute the script as shown for each level.

  26. Justin

    November 28, 2010 at 10:42 pm

    Hi, i’m using the .11 version of the script on a large file (almost 2gig) The file cuts the image just fine but when it tried to do the rename it errors with

    googletilecutter-0.11.sh: line 180: /bin/ls: Argument list too long

    There are 5192 temporary files created, I’m assuming those are the images, but without the rename they are a tad usles. Any ideas?

  27. Ian Stevens

    December 8, 2010 at 10:59 am

    Hi Justin. Unfortunately, the tiles generated from your image outnumber the maximum number of arguments one is able to specify in the command-line. The script is in BASH, and I leverage command-line utils to find and number tiles. I will have to modify the script to support an arbitrary number of tiles. Frankly, I’m surprised that your machine didn’t keel over when tiling that file. How long did it take before it crashed?

  28. Ian Stevens

    January 2, 2011 at 6:59 pm

    Pete, you most certainly will have to transform the map so that it fits to Google’s map projection. Sorry, my tile cutter doesn’t perform such a transformation.

  29. Lambros

    October 20, 2013 at 10:30 am

    Hello, I am going to use your script in a project I am doing with google maps. But I think there is a mistake, or I might be doing something wrong.

    I have an image for zoom level 21 and I got its Tile coordinates from another demo in the google maps website.

    I converted the image for zoom level 20 using ImageMagick ( 50% the size of the original image ) and I tried to create the tiles using your tool. The renaming of the files though I think it’s wrong when I use version 1. I think they should HALF compared to the original coordinates but your script DOUBLES them, which is only the case when you are going in a higher zoom level.

    Am I correct or I oversee something ?
    Thank you