{"id":2378,"date":"2015-03-15T05:34:09","date_gmt":"2015-03-15T05:34:09","guid":{"rendered":"http:\/\/41j.com\/blog\/?p=2378"},"modified":"2015-03-15T05:34:09","modified_gmt":"2015-03-15T05:34:09","slug":"creating-leafletjs-tile-sets-in-golang","status":"publish","type":"post","link":"https:\/\/41j.com\/blog\/2015\/03\/creating-leafletjs-tile-sets-in-golang\/","title":{"rendered":"Creating LeafletJS tile sets in golang"},"content":{"rendered":"<p><a href=\"http:\/\/41j.com\/blog\/wp-content\/uploads\/2015\/03\/esp8266_slip.png\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/41j.com\/blog\/wp-content\/uploads\/2015\/03\/esp8266_slip-1024x516.png\" alt=\"esp8266_slip\" width=\"700\" height=\"353\" class=\"aligncenter size-large wp-image-2379\" srcset=\"https:\/\/41j.com\/blog\/wp-content\/uploads\/2015\/03\/esp8266_slip-1024x516.png 1024w, https:\/\/41j.com\/blog\/wp-content\/uploads\/2015\/03\/esp8266_slip-300x151.png 300w, https:\/\/41j.com\/blog\/wp-content\/uploads\/2015\/03\/esp8266_slip.png 1264w\" sizes=\"auto, (max-width: 700px) 100vw, 700px\" \/><\/a><\/p>\n<p>I wanted to create some slippy map style imageviewers using LeafletJS from large flat images files. In order to do this you need to break the image down into tiles of 256&#215;256 pixels and various zoom levels. There are plenty of tools to do this, but none that looked like they quite fit my application. In anycase I figured it would be an interesting golang learning exercise. The code is available on github <a href=\"https:\/\/github.com\/new299\/tilesplit\">here<\/a>. But it&#8217;s fairly simple and the sourcecode the shown below. It can be ran as:<\/p>\n<pre>\r\nsplit filename.png\r\n<\/pre>\n<p>And will spit out a directory called &#8220;tiles&#8221; which contains the tileset. The html file in the above github repository shows how LeafletJS might be used to view this tileset.<\/p>\n<pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\r\npackage main\r\n\r\nimport (\r\n  &quot;fmt&quot;\r\n  &quot;image&quot;\r\n  &quot;image\/jpeg&quot;\r\n  &quot;image\/png&quot;\r\n  &quot;image\/draw&quot;\r\n  &quot;os&quot;\r\n  &quot;strconv&quot;\r\n  &quot;github.com\/nfnt\/resize&quot;\r\n  &quot;math&quot;\r\n)\r\n\r\nfunc init() {\r\n  \/\/ damn important or else At(), Bounds() functions will\r\n  \/\/ caused memory pointer error!!\r\n  image.RegisterFormat(&quot;jpeg&quot;, &quot;jpeg&quot;, jpeg.Decode, jpeg.DecodeConfig)\r\n  image.RegisterFormat(&quot;png&quot;, &quot;png&quot;, png.Decode, png.DecodeConfig)\r\n}\r\n\r\nfunc make_image_tiles(basepath string,scale int,tile_size int,rescale_size int,rgbimage *image.RGBA) {\r\n  bounds   := rgbimage.Bounds()\r\n  fmt.Println(bounds)\r\n\r\n  path := basepath + &quot;\/&quot; + strconv.Itoa(scale)\r\n  os.Mkdir(path,777);\r\n\r\n  for cx := bounds.Min.X;cx &lt; bounds.Max.X;cx += tile_size {\r\n\r\n  os.Mkdir(path + &quot;\/&quot; + strconv.Itoa(cx\/tile_size),777);\r\n\r\n   for cy := bounds.Min.Y;cy &lt; bounds.Max.Y;cy += tile_size {\r\n  \r\n     \/\/ Grab tile from image\r\n     fmt.Printf(&quot;Get tile %v %v %v %v\\n&quot;,cx,cy,cx+tile_size,cy+tile_size)\r\n     subimage := rgbimage.SubImage(image.Rectangle{image.Point{cx,cy},image.Point{cx+tile_size,cy+tile_size}})\r\n\r\n     subbounds := subimage.Bounds()\r\n     fmt.Println(&quot;subb: &quot;, subbounds)\r\n     x_delta := (subbounds.Max.X-subbounds.Min.X)\r\n     y_delta := (subbounds.Max.Y-subbounds.Min.Y)\r\n     fmt.Println(&quot;delta: &quot;, x_delta,&quot; &quot;,y_delta)\r\n     if (x_delta &lt; tile_size) ||\r\n        (y_delta &lt; tile_size) {\r\n\r\n       newsubimage := image.NewRGBA(image.Rectangle{image.Point{0,0},image.Point{tile_size,tile_size}})\r\n       draw.Draw(newsubimage,image.Rectangle{image.Point{0,0},image.Point{tile_size,tile_size}},subimage,subimage.Bounds().Min,draw.Src)\r\n       subimage = newsubimage\r\n\r\n     }\r\n     fmt.Println(&quot;subdixed: &quot;, subimage.Bounds())\r\n\r\n     if tile_size != rescale_size {\r\n      subimage = resize.Resize(uint(rescale_size),uint(rescale_size), subimage, resize.Lanczos3)\r\n     }\r\n\r\n     \/\/ Write the file to disk\r\n     subfile, _ := os.Create(path + &quot;\/&quot; + strconv.Itoa(cx\/tile_size) + &quot;\/&quot; + strconv.Itoa(cy\/tile_size) + &quot;.png&quot;)\r\n     png.Encode(subfile, subimage) \r\n   }\r\n  }\r\n}\r\n\r\nfunc main() {\r\n  imgfile, err := os.Open(os.Args&#x5B;1])\r\n\r\n  tile_size := 256\r\n  rescale_size := tile_size\r\n\r\n  if err != nil {\r\n    fmt.Println(&quot;file not found!&quot;)\r\n    os.Exit(1)\r\n  }\r\n\r\n  defer imgfile.Close()\r\n\r\n  img, _, _ := image.Decode(imgfile)\r\n\r\n  rgbimage := img.(*image.RGBA)\r\n  bounds   := rgbimage.Bounds()\r\n\r\n  width  := bounds.Max.X - bounds.Min.X\r\n  height := bounds.Max.Y - bounds.Max.Y\r\n\r\n  \/\/ there's no int math.Max in golang\r\n  mdim := math.Max(float64(width),float64(height))\r\n\r\n  scale_max_f := math.Log2(mdim\/float64(tile_size))+1\r\n  scale_max   := int(scale_max_f)\r\n\r\n  os.Mkdir(&quot;.\/tiles&quot;,777);\r\n\r\n  c_tile_size := tile_size\r\n  for scale := scale_max; scale &gt;= 1; scale-- {\r\n    fmt.Printf(&quot;tile size: %v\\n&quot;,c_tile_size)\r\n    make_image_tiles(&quot;.\/tiles&quot;,scale,int(c_tile_size),rescale_size,rgbimage);\r\n    c_tile_size = c_tile_size*2\r\n  }\r\n\r\n}\r\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>I wanted to create some slippy map style imageviewers using LeafletJS from large flat images files. In order to do this you need to break the image down into tiles of 256&#215;256 pixels and various zoom levels. There are plenty of tools to do this, but none that looked like they quite fit my application. [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[1],"tags":[],"class_list":["post-2378","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/p1RRoU-Cm","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/41j.com\/blog\/wp-json\/wp\/v2\/posts\/2378","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/41j.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/41j.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/41j.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/41j.com\/blog\/wp-json\/wp\/v2\/comments?post=2378"}],"version-history":[{"count":2,"href":"https:\/\/41j.com\/blog\/wp-json\/wp\/v2\/posts\/2378\/revisions"}],"predecessor-version":[{"id":2381,"href":"https:\/\/41j.com\/blog\/wp-json\/wp\/v2\/posts\/2378\/revisions\/2381"}],"wp:attachment":[{"href":"https:\/\/41j.com\/blog\/wp-json\/wp\/v2\/media?parent=2378"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/41j.com\/blog\/wp-json\/wp\/v2\/categories?post=2378"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/41j.com\/blog\/wp-json\/wp\/v2\/tags?post=2378"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}