-
-
Save praeclarum/10428983 to your computer and use it in GitHub Desktop.
| using System; | |
| using System.Net; | |
| using System.IO; | |
| using Gdk; | |
| namespace TileSticher | |
| { | |
| class App | |
| { | |
| public static int Main (string[] args) | |
| { | |
| if (args.Length != 5) { | |
| Console.WriteLine ("TileSticher.exe latitude longitude zoom numHorizontal numVertical"); | |
| return 1; | |
| } | |
| // | |
| // Get the root tile | |
| // | |
| var latitude = double.Parse (args [0]); | |
| var longitude = double.Parse (args [1]); | |
| var zoom = int.Parse (args [2]); | |
| var numHorizontal = int.Parse (args [3]); | |
| var numVertical = int.Parse (args [4]); | |
| var t = GetTileIndex (latitude, longitude, zoom); | |
| // | |
| // Download all the tiles | |
| // | |
| var style = SatelliteUrlTemplate; | |
| var xo = -numHorizontal / 2; | |
| var yo = -numVertical / 2; | |
| for (var i = 0; i < numHorizontal; i++) { | |
| for (var j = 0; j < numVertical; j++) { | |
| var index = new Point (t.X + i + xo, t.Y + j + yo); | |
| DownloadTile (style, index, zoom); | |
| } | |
| } | |
| // | |
| // Merge them | |
| // | |
| var rootImage = LoadTile (style, t, zoom); | |
| var width = rootImage.Width; | |
| var height = rootImage.Height; | |
| var outputWidth = width * numHorizontal; | |
| var outputHeight = height * numVertical; | |
| var output = new Pixbuf (Colorspace.Rgb, false, 8, outputWidth, outputHeight); | |
| for (var i = 0; i < numHorizontal; i++) { | |
| for (var j = 0; j < numVertical; j++) { | |
| var index = new Point (t.X + i + xo, t.Y + j + yo); | |
| using (var image = LoadTile (style, index, zoom)) { | |
| image.Composite ( | |
| output, | |
| width * i, height * j, | |
| width, height, | |
| width * i, height * j, | |
| 1, 1, | |
| InterpType.Bilinear, 255); | |
| } | |
| } | |
| } | |
| output.Save ("Poop.png", "png"); | |
| Console.WriteLine ("Created {0}x{1} Poop.png", outputWidth, outputHeight); | |
| return 0; | |
| } | |
| static Pixbuf LoadTile (string style, Point index, int zoom) | |
| { | |
| return new Pixbuf (GetTileFilename (style, index, zoom)); | |
| } | |
| static string GetTileFilename (string style, Point index, int zoom) | |
| { | |
| return string.Format ("{0}-{1}-{2}-{3}.png", index.X, index.Y, zoom, style.Length); | |
| } | |
| static void DownloadTile (string style, Point index, int zoom) | |
| { | |
| var filename = GetTileFilename (style, index, zoom); | |
| if (File.Exists (filename)) | |
| return; | |
| var url = string.Format (style, index.X, index.Y, zoom); | |
| Console.WriteLine ("Downloading {0}", url); | |
| var web = new WebClient (); | |
| web.Headers.Add ("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; .NET CLR 1.0.3705;)"); | |
| web.DownloadFile (url, filename); | |
| } | |
| const string MapUrlTemplate = "https://www.google.com/maps/vt/pb=!1m4!1m3!1i{2}!2i{0}!3i{1}!2m3!1e0!2sm!3i258145710"; | |
| const string SatelliteUrlTemplate = "https://khms2.google.com/kh/v=147&x={0}&y={1}&z={2}"; | |
| static Point GetTileIndex (double latitude, double longitude, int zoom) | |
| { | |
| var lat_rad = latitude / 180 * Math.PI; | |
| var n = 1 << zoom; | |
| var xtile = n * ((longitude + 180) / 360); | |
| var ytile = n * (1 - (Math.Log (Math.Tan (lat_rad) + 1/Math.Cos (lat_rad)) / Math.PI)) / 2; | |
| return new Point ((int)xtile, (int)ytile); | |
| } | |
| } | |
| } |
@sleirgoevy Can you please post 2 example URLs, one for the normal map tile and one for the satellite map tile, which when accessed with the browser serve an image correctly? Any coordinates, I just want some baseline for comparison. I must be doing something wrong on my end, but when I tried this, all I got were 404/403 responses.
Normal map: https://www.google.com/maps/vt/pb=!1m4!1m3!1i0!2i0!3i0!2m3!1e0!2sm!3i0
Satellite: https://khms3.google.com/kh/v=845?x=0&y=0&z=0
The normal link works (for me) both in browser and using cURL. The second only worked in browser, however spoofing the User-Agent header seems to be enough to retrieve the image.
I suppose Google may be restricting these APIs to specific countries, so you may be able to query these URLs via a VPN or proxy.
Thank you!
I believe the v parameter may be a version number. If I check a loaded tile in the browser inspector, and bump the version of the URL in the comment above, the URL loads correctly. Otherwise, it 404s. There are also several KHMS domains. I don't know if they're based on location, and thus may have different availability for different folks, or functioning as a simple load-balancer.
I have forked into javascript in case of any use; it can be used from Google Apps Script from e.g. a spreadsheet.
@TomasHubelbauer, you are wrong. The URL in question still works and returns plain images.