Moved sub baseline tile generation into separate file.

This commit is contained in:
Sascha L. Teichmann 2014-09-17 17:20:07 +02:00
parent cf0aec6fa5
commit 29845a259d
2 changed files with 162 additions and 146 deletions

View File

@ -7,71 +7,12 @@ package main
import ( import (
"flag" "flag"
"fmt" "fmt"
"image"
"image/color"
"image/png"
"log" "log"
"net/http" "net/http"
"os"
"path/filepath"
"strconv"
"bitbucket.org/s_l_teichmann/mtredisalize/common"
"github.com/gorilla/mux" "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() { func main() {
var ( var (
port int port int
@ -91,92 +32,9 @@ func main() {
flag.Parse() flag.Parse()
r := mux.NewRouter() r := mux.NewRouter()
r.HandleFunc("/map/{z:[0-9]+}/{x:[0-9]+}/{y:[0-9]+}.png", func(rw http.ResponseWriter, r *http.Request) { r.HandleFunc("/map/{z:[0-9]+}/{x:[0-9]+}/{y:[0-9]+}.png",
func(rw http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r) createTiles(rw, r, mapDir)
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.PathPrefix("/").Handler(http.FileServer(http.Dir(webDir))) r.PathPrefix("/").Handler(http.FileServer(http.Dir(webDir)))

View 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)
}