mirror of
				https://bitbucket.org/s_l_teichmann/mtsatellite
				synced 2025-11-04 09:55:34 +01:00 
			
		
		
		
	Moved sub baseline tile generation into separate file.
This commit is contained in:
		@@ -7,71 +7,12 @@ package main
 | 
			
		||||
import (
 | 
			
		||||
	"flag"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"image"
 | 
			
		||||
	"image/color"
 | 
			
		||||
	"image/png"
 | 
			
		||||
	"log"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"os"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
	"strconv"
 | 
			
		||||
 | 
			
		||||
	"bitbucket.org/s_l_teichmann/mtredisalize/common"
 | 
			
		||||
 | 
			
		||||
	"github.com/gorilla/mux"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func blowUp(src image.Image) *image.RGBA {
 | 
			
		||||
 | 
			
		||||
	// TODO: Fast path for image.RGBA
 | 
			
		||||
 | 
			
		||||
	dst := image.NewRGBA(image.Rect(0, 0, 256, 256))
 | 
			
		||||
 | 
			
		||||
	// fix point numbers x:8
 | 
			
		||||
	dx, dy := src.Bounds().Dx(), src.Bounds().Dy()
 | 
			
		||||
 | 
			
		||||
	bx, by := src.Bounds().Min.X<<8, src.Bounds().Min.Y<<8
 | 
			
		||||
 | 
			
		||||
	py := by
 | 
			
		||||
	for y := 0; y < 256; y++ {
 | 
			
		||||
		sy := (py >> 8) & 0xff
 | 
			
		||||
		ox := -1
 | 
			
		||||
		px := bx
 | 
			
		||||
		var col color.Color
 | 
			
		||||
		for x := 0; x < 256; x++ {
 | 
			
		||||
			sx := (px >> 8) & 0xff
 | 
			
		||||
			if sx != ox { // Minimize interface indirection access.
 | 
			
		||||
				ox = sx
 | 
			
		||||
				col = src.At(sx, sy)
 | 
			
		||||
			}
 | 
			
		||||
			dst.Set(x, y, col)
 | 
			
		||||
			px += dx
 | 
			
		||||
		}
 | 
			
		||||
		py += dy
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return dst
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func toUint(s string) uint {
 | 
			
		||||
	var err error
 | 
			
		||||
	var x int
 | 
			
		||||
	if x, err = strconv.Atoi(s); err != nil {
 | 
			
		||||
		log.Printf("WARN: Cannot convert to int: %s", err)
 | 
			
		||||
		return 0
 | 
			
		||||
	}
 | 
			
		||||
	return uint(x)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func createETag(path string) (etag string, err error) {
 | 
			
		||||
	var fi os.FileInfo
 | 
			
		||||
	if fi, err = os.Stat(path); err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	etag = fmt.Sprintf("%x-%x", fi.ModTime().Unix(), fi.Size())
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func main() {
 | 
			
		||||
	var (
 | 
			
		||||
		port   int
 | 
			
		||||
@@ -91,93 +32,10 @@ func main() {
 | 
			
		||||
	flag.Parse()
 | 
			
		||||
 | 
			
		||||
	r := mux.NewRouter()
 | 
			
		||||
	r.HandleFunc("/map/{z:[0-9]+}/{x:[0-9]+}/{y:[0-9]+}.png", func(rw http.ResponseWriter, r *http.Request) {
 | 
			
		||||
 | 
			
		||||
		vars := mux.Vars(r)
 | 
			
		||||
		xs := vars["x"]
 | 
			
		||||
		ys := vars["y"]
 | 
			
		||||
		zs := vars["z"]
 | 
			
		||||
 | 
			
		||||
		x, y, z := toUint(xs), toUint(ys), toUint(zs)
 | 
			
		||||
		if z < 9 {
 | 
			
		||||
			filename := fmt.Sprintf("%d/%d/%d.png", z, x, y)
 | 
			
		||||
			http.ServeFile(rw, r, filepath.Join(mapDir, filename))
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if z > 16 {
 | 
			
		||||
			z = 16
 | 
			
		||||
		}
 | 
			
		||||
		tx := x >> (z - 8)
 | 
			
		||||
		ty := y >> (z - 8)
 | 
			
		||||
 | 
			
		||||
		baseTile := filepath.Join(mapDir, fmt.Sprintf("8/%d/%d.png", tx, ty))
 | 
			
		||||
 | 
			
		||||
		var etag string
 | 
			
		||||
		var err error
 | 
			
		||||
 | 
			
		||||
		if ifNoneMatch := r.Header.Get("If-None-Match"); ifNoneMatch != "" {
 | 
			
		||||
			if etag, err = createETag(baseTile); err != nil {
 | 
			
		||||
				http.NotFound(rw, r)
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
			if ifNoneMatch == etag {
 | 
			
		||||
				http.Error(rw, http.StatusText(http.StatusNotModified), http.StatusNotModified)
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		img := common.LoadPNG(baseTile)
 | 
			
		||||
 | 
			
		||||
		type subImage interface {
 | 
			
		||||
			SubImage(image.Rectangle) image.Image
 | 
			
		||||
		}
 | 
			
		||||
		var si subImage
 | 
			
		||||
		var ok bool
 | 
			
		||||
		if si, ok = img.(subImage); !ok {
 | 
			
		||||
			// Should not happen.
 | 
			
		||||
			http.Error(rw,
 | 
			
		||||
				http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		rx := x & ^(^uint(0) << (z - 8))
 | 
			
		||||
		ry := y & ^(^uint(0) << (z - 8))
 | 
			
		||||
 | 
			
		||||
		parts := uint(1) << (z - 8)
 | 
			
		||||
 | 
			
		||||
		w := uint(256) / parts
 | 
			
		||||
		xo := w * rx
 | 
			
		||||
		yo := w * (parts - 1 - ry)
 | 
			
		||||
		//fmt.Printf("x %d\n", x)
 | 
			
		||||
		//fmt.Printf("y %d\n", y)
 | 
			
		||||
		//fmt.Printf("z %d\n", z)
 | 
			
		||||
		//fmt.Printf("z %d\n", z)
 | 
			
		||||
		//fmt.Printf("parts %d\n", parts)
 | 
			
		||||
		//fmt.Printf("w %d\n", w)
 | 
			
		||||
		//fmt.Printf("xo %d\n", xo)
 | 
			
		||||
		//fmt.Printf("yo %d\n", yo)
 | 
			
		||||
		//fmt.Printf("rx %d\n", rx)
 | 
			
		||||
		//fmt.Printf("ry %d\n", ry)
 | 
			
		||||
 | 
			
		||||
		img = si.SubImage(image.Rect(int(xo), int(yo), int(xo+w), int(yo+w)))
 | 
			
		||||
		img = blowUp(img)
 | 
			
		||||
 | 
			
		||||
		rw.Header().Set("Content-Type", "image/png")
 | 
			
		||||
		if etag == "" {
 | 
			
		||||
			if etag, err = createETag(baseTile); err != nil {
 | 
			
		||||
				log.Printf("Cannot create ETag: %s", baseTile)
 | 
			
		||||
			} else {
 | 
			
		||||
				rw.Header().Set("ETag", etag)
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			rw.Header().Set("ETag", etag)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if err = png.Encode(rw, img); err != nil {
 | 
			
		||||
			log.Printf("WARN: encoding image failed: %s", err)
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
	})
 | 
			
		||||
	r.HandleFunc("/map/{z:[0-9]+}/{x:[0-9]+}/{y:[0-9]+}.png",
 | 
			
		||||
		func(rw http.ResponseWriter, r *http.Request) {
 | 
			
		||||
			createTiles(rw, r, mapDir)
 | 
			
		||||
		})
 | 
			
		||||
 | 
			
		||||
	r.PathPrefix("/").Handler(http.FileServer(http.Dir(webDir)))
 | 
			
		||||
	http.Handle("/", r)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										158
									
								
								cmd/mtwebmapper/subbaseline.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										158
									
								
								cmd/mtwebmapper/subbaseline.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,158 @@
 | 
			
		||||
// Copyright 2014 by Sascha L. Teichmann
 | 
			
		||||
// Use of this source code is governed by the MIT license
 | 
			
		||||
// that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package main
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"image"
 | 
			
		||||
	"image/color"
 | 
			
		||||
	"image/png"
 | 
			
		||||
	"log"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"os"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
	"strconv"
 | 
			
		||||
 | 
			
		||||
	"bitbucket.org/s_l_teichmann/mtredisalize/common"
 | 
			
		||||
	"github.com/gorilla/mux"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func blowUp(src image.Image) *image.RGBA {
 | 
			
		||||
 | 
			
		||||
	// TODO: Fast path for image.RGBA
 | 
			
		||||
 | 
			
		||||
	dst := image.NewRGBA(image.Rect(0, 0, 256, 256))
 | 
			
		||||
 | 
			
		||||
	// fix point numbers x:8
 | 
			
		||||
	dx, dy := src.Bounds().Dx(), src.Bounds().Dy()
 | 
			
		||||
 | 
			
		||||
	bx, by := src.Bounds().Min.X<<8, src.Bounds().Min.Y<<8
 | 
			
		||||
 | 
			
		||||
	py := by
 | 
			
		||||
	for y := 0; y < 256; y++ {
 | 
			
		||||
		sy := (py >> 8) & 0xff
 | 
			
		||||
		ox := -1
 | 
			
		||||
		px := bx
 | 
			
		||||
		var col color.Color
 | 
			
		||||
		for x := 0; x < 256; x++ {
 | 
			
		||||
			sx := (px >> 8) & 0xff
 | 
			
		||||
			if sx != ox { // Minimize interface indirection access.
 | 
			
		||||
				ox = sx
 | 
			
		||||
				col = src.At(sx, sy)
 | 
			
		||||
			}
 | 
			
		||||
			dst.Set(x, y, col)
 | 
			
		||||
			px += dx
 | 
			
		||||
		}
 | 
			
		||||
		py += dy
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return dst
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func createTiles(rw http.ResponseWriter, r *http.Request, mapDir string) {
 | 
			
		||||
	vars := mux.Vars(r)
 | 
			
		||||
	xs := vars["x"]
 | 
			
		||||
	ys := vars["y"]
 | 
			
		||||
	zs := vars["z"]
 | 
			
		||||
 | 
			
		||||
	x, y, z := toUint(xs), toUint(ys), toUint(zs)
 | 
			
		||||
	if z < 9 {
 | 
			
		||||
		filename := fmt.Sprintf("%d/%d/%d.png", z, x, y)
 | 
			
		||||
		http.ServeFile(rw, r, filepath.Join(mapDir, filename))
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if z > 16 {
 | 
			
		||||
		z = 16
 | 
			
		||||
	}
 | 
			
		||||
	tx := x >> (z - 8)
 | 
			
		||||
	ty := y >> (z - 8)
 | 
			
		||||
 | 
			
		||||
	baseTile := filepath.Join(mapDir, fmt.Sprintf("8/%d/%d.png", tx, ty))
 | 
			
		||||
 | 
			
		||||
	var etag string
 | 
			
		||||
	var err error
 | 
			
		||||
 | 
			
		||||
	if ifNoneMatch := r.Header.Get("If-None-Match"); ifNoneMatch != "" {
 | 
			
		||||
		if etag, err = createETag(baseTile); err != nil {
 | 
			
		||||
			http.NotFound(rw, r)
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		if ifNoneMatch == etag {
 | 
			
		||||
			http.Error(rw, http.StatusText(http.StatusNotModified), http.StatusNotModified)
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	img := common.LoadPNG(baseTile)
 | 
			
		||||
 | 
			
		||||
	type subImage interface {
 | 
			
		||||
		SubImage(image.Rectangle) image.Image
 | 
			
		||||
	}
 | 
			
		||||
	var si subImage
 | 
			
		||||
	var ok bool
 | 
			
		||||
	if si, ok = img.(subImage); !ok {
 | 
			
		||||
		// Should not happen.
 | 
			
		||||
		http.Error(rw,
 | 
			
		||||
			http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	rx := x & ^(^uint(0) << (z - 8))
 | 
			
		||||
	ry := y & ^(^uint(0) << (z - 8))
 | 
			
		||||
 | 
			
		||||
	parts := uint(1) << (z - 8)
 | 
			
		||||
 | 
			
		||||
	w := uint(256) / parts
 | 
			
		||||
	xo := w * rx
 | 
			
		||||
	yo := w * (parts - 1 - ry)
 | 
			
		||||
	//fmt.Printf("x %d\n", x)
 | 
			
		||||
	//fmt.Printf("y %d\n", y)
 | 
			
		||||
	//fmt.Printf("z %d\n", z)
 | 
			
		||||
	//fmt.Printf("z %d\n", z)
 | 
			
		||||
	//fmt.Printf("parts %d\n", parts)
 | 
			
		||||
	//fmt.Printf("w %d\n", w)
 | 
			
		||||
	//fmt.Printf("xo %d\n", xo)
 | 
			
		||||
	//fmt.Printf("yo %d\n", yo)
 | 
			
		||||
	//fmt.Printf("rx %d\n", rx)
 | 
			
		||||
	//fmt.Printf("ry %d\n", ry)
 | 
			
		||||
 | 
			
		||||
	img = si.SubImage(image.Rect(int(xo), int(yo), int(xo+w), int(yo+w)))
 | 
			
		||||
	img = blowUp(img)
 | 
			
		||||
 | 
			
		||||
	rw.Header().Set("Content-Type", "image/png")
 | 
			
		||||
	if etag == "" {
 | 
			
		||||
		if etag, err = createETag(baseTile); err != nil {
 | 
			
		||||
			log.Printf("Cannot create ETag: %s", baseTile)
 | 
			
		||||
		} else {
 | 
			
		||||
			rw.Header().Set("ETag", etag)
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		rw.Header().Set("ETag", etag)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err = png.Encode(rw, img); err != nil {
 | 
			
		||||
		log.Printf("WARN: encoding image failed: %s", err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func createETag(path string) (etag string, err error) {
 | 
			
		||||
	var fi os.FileInfo
 | 
			
		||||
	if fi, err = os.Stat(path); err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	etag = fmt.Sprintf("%x-%x", fi.ModTime().Unix(), fi.Size())
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func toUint(s string) uint {
 | 
			
		||||
	var err error
 | 
			
		||||
	var x int
 | 
			
		||||
	if x, err = strconv.Atoi(s); err != nil {
 | 
			
		||||
		log.Printf("WARN: Cannot convert to int: %s", err)
 | 
			
		||||
		return 0
 | 
			
		||||
	}
 | 
			
		||||
	return uint(x)
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user