Sunday, July 3, 2011

Create Zoomable Images Using The Google Maps API




I visited the Google+ Project website the other day and to my surprise, it was powered by the Google Maps engine! It is somewhat creative to re-use the Maps engine for any purpose other than mapping. It is just beautiful.

It also reminds me of the Art Project I've seen a while back that uses the Street View engine. A must see.

Anyways, I'm pleased to show you two samples today: they both let you navigate into an image using the Google Maps engine. I'm also giving up the necessary tools to do it yourself. Enjoy!

Table of Contents




Introduction


Hi,

I've decided today to create small Google Maps samples that lets you zoom in and out of two pictures. As I said, I'm giving all the code to reproduce them including a small command line utility that lets you generate, from a source picture, the tiles your map needs to zoom into it. Pretty nice huh?


Sample #1 - Earth


Yes! what you're seeing at the top of this article is actually a Google Maps map! The map contains only custom controls for a richer user experience. Go back to the top if you missed it...

Let's look at a more simple example this time:


Sample #2 - Lara Croft





Possible Applications


The two samples are pretty cool but aren't very useful as they are. But maybe we can think of some possible applications of this technology for...

  • online installation manuals, where you can zoom and interact with some components
  • museums, to display pieces of art in great details
  • learning, by exploring the different layers of something
  • any product showcase, to show in details the features of a product
  • etc...

There's plenty of possible applications and if you're thinking about something interesting, feel free to share your ideas by leaving a comment below!


How it works


If you're not a Google Maps API guru, you may find the recommended reading section of this article quite useful.

Technically, this is pretty simple. At the zoom level 0 (zero). Google Maps displays a single 256px square tile representing "the world" (your whole object). As you zoom to the level 1, Google Maps shows the equivalent of your original tile zoomed to 200%: a 512px square area. But it is not your original 256px tile that is stretched by 200% to fill that area, what happens is that 4 new 256px tiles are loaded. So the same picture is shown, but it has four times the resolution and since the map's viewing area stays the same size, you have the impression that the picture has been zoomed in. At any zoom level, you can find the number of tiles there are on each side of the map with this formula: 2zoom.

The idea here is to find a picture large enough to cover the zoom level 4 or 5 (4096 by 4096 or 8192 by 8192). Then use my utility to split that picture recursively at each zoom level into 256px tiles.

After that it is only a matter of telling Google Maps API to use your tiles instead of the default ones.


HTML/JavaScript Code - Both Samples


This is a complete example of an HTML file containing my 2 samples. Just copy and paste the code into a local .html and open it with your favorite browser. UPDATE: An html file has been provided in the Related Downloads section. If you're looking for the tiles generator, it's here.


C# Code - Tiles Generation


Copy and paste the following C# code into a new Console Application project (lets say "TilesGenerator"). UPDATE: A compiled version has been provided in the Related Downloads section. You can invoke the program like this:

TilesGenerator.exe [maxzoom] [filename]

Where [maxzoom] represents the maximum zoom level you want to achieve. And [filename] represents your huge picture from which you want to generate the tiles for each zoom level.

Remember, at zoom level...

0, you have 1 (256px wide) tile
1, you have 4 tiles
2, you have 16 tiles
3, you have 64 tiles
4, you have 256 tiles
5, you have 1,024 tiles
[...]

So if you choose level 5, the program will resize your original picture to 8192px by 8192px (32 by 32 tiles) and will generate all the 1,024 tiles for that level. It will then resize your original image to 4096px by 4096px to generate the 256 required tiles for the zoom level 4. It will proceed as such for the remaining zoom level until reaching zoom level 0. At the end, you'll be having 1 + 4 + 16 + 64 + 256 + 1024 = 1,365 tiles. It's best to use a square picture.


Credits




Recommended Reading


A great book that I can recommend you is a plain JavaScript book called . This is THE book to have if you want to master the basics of JavaScript. Even today, I can open up the book at any page and learn or re-learn something useful. JavaScript is so rich, having an in-depth knowledge of it is the key to success to build great applications with any library.

Then if you're a beginner with Google Maps API v3, you will definitely find interesting . One reviewer actually said: "The online documentation of the google maps api 3 is pretty good, but I definitely found that using this book helped me get my project done alot faster."


Conclusion


Thank you for reading, don't forget to like the article (if you really did) and buy your books from if you're a reader :) It encourages me to write more and more articles on this blog.

Again, thank you for being here.


Related Downloads


File Name Description Size
index.html Google Maps Demos 11.7 KB download
license.txt TilesGenerator.exe license 799 bytes download
TilesGenerator.exe TilesGenerator Compiled Executable 6.50 KB download
TilesGenerator.zip MS Visual C# 2010 Express Sources 8.56 KB download


Related Articles


53 comments:

moussan said...

Hi, thank you for the excellent guide. I am new to programming. let alone C#. When i try to build the code in visual C# 2010 express, i get 31 errors.

for example;
The type or namespace "Drawing" does not exist in the namespace 'system' (are you missing an assembly reference?)

can you help me compile and run this code. I am better at JavaScript and HTML.

Hi, thanks for reading!

You have to include "System.Drawing" as a reference to your console application!

Let me know if I can be of any further help

Mike

moussan said...

Hi,
So i managed to take my first baby steps in the world of visual C# programming and using the visual studio express tools.

First I added the 'System.Drawing' Reference through the solution explorer. Then i 'Build' the program.

When i use it through the command console i receive the following error.

C:\C#>TilesGenerator.exe 5 PB-profile.png

Parameter is not valid.


I hope i am not troubling you with my simple questions.

Moussa

Anonymous Avatar Anonymous said...

hi mike,
great article - thanks.

i had same as moussan - parameter error, thought it was something duff with png codecs on my system or similar issue but decided that is was the encoding parameters.

within "SavePNG" I replaced

EncoderParameters encoderParams = new EncoderParameters(0);
img.Save(path, codecInfo, encoderParams);

with

System.Drawing.Imaging.Encoder myEncoder = System.Drawing.Imaging.Encoder.Quality;
EncoderParameters myEncoderParameters = new EncoderParameters(1);
EncoderParameter myEncoderParameter = new EncoderParameter(myEncoder, 0L);
myEncoderParameters.Param[0] = myEncoderParameter;
img.Save(path, codecInfo, myEncoderParameters);

and it worked - moussan give that ago...

otherwise thanks again,
AJP

Congrats!

Thank you very much for stopping by!

moussan said...

AJP - Thank you, it worked like a charm.

Mike - thank you for your guide.

Once i am done with my website, i will come back to show you guys.

Moussan

That is great and good news, can't wait to see what you have for us!

LockeVN said...

It works like a charm, and your code is awesome. Thanks.

Using Google Maps API like this make me feel we have Prezi (with Flash) alike in HTML and JS.

I will make a demo in my next hackday ;))

Anonymous Avatar Anonymous said...

hi

ı don't understand

for example
Console.WriteLine("usage: \"TilesGenerator.exe [4] [C:\\users\\xx\\Desktop\\image.png]\"");

in program?

It tells you how you can invoke the console application...

The first parameter is the zoom depth you want your map to be, the second parameter is the path of the big picture you want to take your tiles from..

If your second parameter (path) contains spaces, you must enclose it in double quotes!

I hope this helps

Thanks

Mark T said...

hello,

I am trying to build an image map into the background of my website. I followed all the instructions, everything is great. tile creation, etc... but the tile pics dont appear on the html page, all i see is empty boxes with broken image placeholders. zooming works, but no images are loading. i made sure the path is defined correctly.
path/tile_zoom_x-y.png
any advice?

Guy said...

Firstly thanks for this extremely well timed post...

My current project is for a charity who wish to promote Public services to the under 25's. They have also drawn the area out by hand. I believe that is something like 10x7 a4 pages... So pretty good for making use of your project...

I've never got involved with c# though and this has been a little stretch for me... Here's what i've done so far:

1) downloaded and installed "Visual C# 2010 Express"
2)Started a new "Console Application" and named "TilesGenerator"
3)Pasted your code into the page (overwriting what was there by default). I also replaced the original "image.save" code as suggested by AJP..
4)Using the "solutions explorer" I right clicked "TilesGenerator" and selected "add Referance"
5) Clicked the ".net" tab, scrolled to and selected System.drawing and hit OK.
6) Right clicked "TilesGenerator" again in "solutions explorer" but this time selected "Build" - "Build Successful"
7) I then run cmd.exe
8) Entered "TilesGenerator.exe 5 c:\LargeMap.png

However i get: 'TilesGenerator.exe' is not a recognised as an internal or external command, operable program or batch file

Any guidance would be much appreciated...

Thanks in advanced,
Guy

Guy said...

Hi,

I had to change the directory in command to where "Visual C# 2010 Express" had saved the built application...

For me this was:

C:\Users\[user name]\Documents\Visual Studio 2010\Projects\TilesGenerator\TilesGenerator\bin\Release

Hope this helps others with limited experience with C#

Mike: Thanks a million for your post... I'll email you the site link once I've developed it... Will certainly mention you when writing the site up on my portfolio...

Bye for now,
Guy

@Mark T: Have you tried looking at the "net" tab of Firebug in Firefox? It will tell you where your browser is trying to get the images from:

http://images.theblog.ca/2011/06/firebug_net_tab.png

(The filename will be in red if not found)

Let me know if there's anything..

@Guy: I'm glad you sorted things out before I had the chance to, I was away from my computer!

Thanks to both of you for your comments! I'm looking forward to see your maps!

Mark T said...

Problem Solved.
"earth" was being prefixed to all file names of the tiles, when the pics are called on the html page.

i think due to this part of the code in the C# file:
// Set custom tiles
this._map.mapTypes.set('earth', new Demo.ImgMapType('earth', '#FFF'));
this._map.setMapTypeId('earth');

and

this part of the code in the html/javascript file

img.src = Demo.Utils.GetImageUrl(this._theme + 'tile_' + zoom + '_' + coord.x + '-' + coord.y + '.png');


i corrected by making the Tilegenerator program, name the tiles correctly with the prefix.

just wanted to share.

I feel dumb here but I do not seem to be able to access your link to your tool that creates the pyramid tiles for the images. It just takes me to the blogger home page.

Has something changed?

The code is embedded in the page, you have to compile your own executable by copying and pasting it in a Console Application!

I should have provided a compiled version, my mistake!

Zoran said...

Thank you very much!!!

Any chance a compiled version could be uploaded? Im not a developer so I dont have the tools or the knowledge, however use of the maps API sounds fun :P

Awesome read anyway, exciting project :)

Sure I'll do it tonight!

Stay tuned and thanks

There you go! All the necessary files in one section.

Happy mapping!

Anonymous Avatar Anonymous said...

I'm on OSX.. but after downloading Mono (stable release), the compiled version works like a charm. Amazing... thanks Mike!!

its quite good tutorial,
i try to customize it for my own .png files. it works!!

any body please provide the shortest code for all ,
because there are two maps, earth and croft added, but i want to edit for one.. and want to delete unnecessary codes from script..
>>>

Awesome. stuff.
Do you happen to know if Google considers it legal to develop google.map apps that use non-map images?

Hi and thanks for the comment!

I will give you my personal opinion and it does not constitute a legal advice and can't be used against me. I do not represent Google in any way :) It is just my experience with a site I've put up online a while back.

But when reading the section 8.1 of the terms (http://code.google.com/apis/maps/terms.html), I think that the custom tiles falls into the "Your Content" category.

So I think it means you are responsible for the tiles you are putting on. If they are ok, then it's ok.

Most sites are doing this: they provide the frame, you provide the content. They can't be held responsible for the user generated content because it remains the property of the user (as per the agreement).

So if you put anything illegal, you would be the one being sued, not Google.

This way, sites don't have to write a clause in their agreement about every single possible things that could appear on it. And it makes the ppl sue each other instead of being sued.

Again, this is my opinion and this comment does not constitute a legal advice!

Thanks!

Matthew said...

Thanks Mike for this awesome generator.

I'm wondering whether you've worked out a way to make the images look nice on the retina display for some iOS devices?

I'll check it out..

But to make the images smoother and visually better (on every platform), I believed I had a bug when I set InterpolationMode.HighQualityBicubic for the InterpolationMode of the Graphics while saving the PNG.

(Line 106 of Program.cs)

Matthew said...

I tried setting it to InterpolationMode.HighQualityBicubic and I didn't see a noticeable difference on the iPhone. I wonder whether I'm coming at this from the wrong angle. I wonder if it would be possible with JavaScript to set the tile size to be 128x128 for the iPhone/iPad? Similar to using the CSS background-size property.

Matthew said...

I'm still testing, but here are the changes I made to the JavaScript to make the graphics look good on a retina display.

// !Added different center for retina display
if(window.devicePixelRatio >= 2) {
var myLatlng = new google.maps.LatLng(66, -90);
} else {
var myLatlng = new google.maps.LatLng(0, -20);
}

// Create map
this._map = new google.maps.Map(container, {
zoom: 1,
center: myLatlng,
mapTypeControl: false,
streetViewControl: false
});

and

// !Added check for retina display
if(window.devicePixelRatio >= 2) {
Demo.ImgMapType.prototype.tileSize = new google.maps.Size(128, 128);
} else {
Demo.ImgMapType.prototype.tileSize = new google.maps.Size(256, 256);
}

Hi Matthew,

Thanks for sharing with us your code!

Josh Lien said...

Hi Mike,

Thank you so much for taking the time to write this post. Your tile generator is perfect (thanks for providing the source). One question, I tried to bump the max zoom to 6 (instead of 5). I changed the logic in the if statement but am still getting "Parameter is not valid" after building. Am I missing something simple?

Thanks again!

Hi and thanks for the comments :)

It should do the trick, line 39 of Program.cs, change 5 for 6.

Let me know if it's still doesn't work.

Thanks

Josh Lien said...

Thanks for responding. Yes, that's the value I changed. After building, I receive "Parameter is not valid". I'll troubleshoot this later today and post back this weekend. Have a good one.

Josh Lien said...

Found my problem! My image resolution was too large at the zoom level I was choosing. I didn't have enough physical memory (including my swap file) to process the bitmap. Hope this helps anyone else getting "Parameter is not valid" while running Mike's (awesome) Tile Generator.

Wow thanks for sharing that with us.. I really was wondering what could be happening.

I hope you will post a link of your (awesome) project when done ;)

Thanks!

Miguel said...

mike im a down right idiot ill be honest. Im trying your tile utility and i just cant get it towork? im windows 7 64 bit machine. i'm trying to use your compile version.
[3]["C:\Users\JAM\Documents\YOUARE HERE\upperLevelImg"]
but im getting no where can you give a noob a helping hand.

Miguel said...

i finally noticed i was not passing the paremeters correctly mike. thanks. now im stuck trying to get the file to read my images...

http://cdn.mikecouturier.com/blog.mikecouturier.com/images/maps-tiles/

Miguel said...

hey mike one question. i have tile my images. and i have put them on a directory image on the root of my site however when i change the location from
'http://cdn.mikecouturier.com/blog.mikecouturier.com/images/maps-tiles/';

to 'image'
my images dont display. can you give me a bump and tell me what i can possibly be doing wrong.

Arjan Duijs said...

Hey Mike,
thanks for the great example.
I am currently playing a bit with the code and trying to get/(re)set the bounderies (so the image doesnt pan outside the viewport).
I have tried to put the listeners and eventfuntion in the Earthmap class .. wel actually i hace tried to put it everywhere.. but without any luck.

any suggestion on where and how to accomplish that?

NATO24 said...

Thanks for sharing your awesome work Mike, helped me tremendously.

-Nathan

Anonymous Avatar Anonymous said...

Hi,

We need to know how to limit the zoom level,it is zooming to infinity.

In my iPad it is zooming to infinity,


I want to use only the image in the window not the total space

When creating the map, you can set some MapOptions including "maxZoom" and "minZoom". (http://code.google.com/apis/maps/documentation/javascript/reference.html#Map)

Concerning restricting the panning of the map to a certain area, there are some workarounds including: http://stackoverflow.com/questions/3125065/how-do-i-limit-panning-in-google-maps-api-v3

Thanks for reading!

http://campus.ciit.net.pk

see & comments plz...

Pedro said...

Amazing post Mike! Thanks! I'm just starting, so it's really useful.

Just one question, is it possible to add links to some areas of the image?

For example, if you click in Lara's head, you go to a site and if you click in one hand you go to a different site.

Is it possible? Thanks!

Yes check out markers or overlays in the Maps Api documentation! Thanks for reading!

Using this method you outline (which works very well,

How do you disable the streetview icon in the navigation controls?

In the Map Options (while creating the map), you can set a flag like:

{
[...]
streetViewControl: false
}

See: http://code.google.com/apis/maps/documentation/javascript/controls.html#Adding_Controls_to_the_Map

Thanks for reading!

I had tried that in this implementation, that you example, and for some reason it causes the entire map to stop rendering.

Still trying to figure out what went wrong.

Thanks for the info though

I did not tried it but this isn't working?

this._map = new google.maps.Map(container, {
  zoom: 1,
  center: new google.maps.LatLng(0, -20),
  mapTypeControl: false,
  streetViewControl: false
});

I'll check this out tonight if you can't get it working...

Thanks

Actually I got it just now.. silly commas.

Thanks! - now just need to add a logo in the corner, and some text. (copyright)

looks amazing when its fucntioning.

check out: http://www.maritimedw.com/products/windows/decorative for a demo (click on configuration examples)

Wow your app is pretty cool :)

I knew it was the comma ;) Happens to me a lot also...

I'm thankful you took the time to share your work with us (a real-world project)

Have you tried a white background in your maps?

Thanks again

Hint: for the logo and the text, I would use custom controls for easy positioning.

Check the first sample and

http://code.google.com/apis/maps/documentation/javascript/controls.html#CustomControls

©2009-2011 Mike Gleason jr Couturier All Rights Reserved