From 5ee3731a27e2b94b09b89fa5003370b7ec6608e0 Mon Sep 17 00:00:00 2001 From: "Sascha L. Teichmann" Date: Sun, 8 May 2016 12:33:17 +0200 Subject: [PATCH] Started with experimental hashing of base tiles to avoid redundant write operations and pyramid updates. --- common/basetilehash.go | 42 +++++++++++++++++++++++++++++++++++ common/image.go | 50 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+) create mode 100644 common/basetilehash.go diff --git a/common/basetilehash.go b/common/basetilehash.go new file mode 100644 index 0000000..506c464 --- /dev/null +++ b/common/basetilehash.go @@ -0,0 +1,42 @@ +// Copyright 2016 by Sascha L. Teichmann +// Use of this source code is governed by the MIT license +// that can be found in the LICENSE file. + +package common + +import ( + "bytes" + "image" + "sync" +) + +type btPos struct { + x int + y int +} + +type BaseTileHash struct { + // XXX: Maybe use some kind of LRU cache instead? + hashes map[btPos][]byte + sync.Mutex +} + +func NewBaseTileHash() *BaseTileHash { + return &BaseTileHash{hashes: map[btPos][]byte{}} +} + +func (bth *BaseTileHash) Update(x, y int, img image.Image) bool { + hash := SHA1Image(img) + key := btPos{x, y} + bth.Lock() + defer bth.Unlock() + if old, found := bth.hashes[key]; found { + equals := bytes.Equal(old, hash) + if !equals { + bth.hashes[key] = hash + } + return !equals + } + bth.hashes[key] = hash + return true +} diff --git a/common/image.go b/common/image.go index dcf3211..45f2a01 100644 --- a/common/image.go +++ b/common/image.go @@ -7,6 +7,7 @@ package common import ( "bufio" "bytes" + "crypto/sha1" "errors" "image" "image/color" @@ -110,3 +111,52 @@ func LoadPNG(path string, bg color.RGBA) image.Image { } return img } + +func sha1rgba(img *image.RGBA) []byte { + hash := sha1.New() + w, h := img.Rect.Dx()*4, img.Rect.Dy() + + pos := img.PixOffset(img.Rect.Min.X, img.Rect.Min.Y) + + for ; h > 0; h, pos = h-1, pos+img.Stride { + hash.Write(img.Pix[pos : pos+w]) + } + + return hash.Sum(nil) +} + +func sha1uniform(img *image.Uniform) []byte { + r, g, b, a := img.C.RGBA() + return sha1.New().Sum([]byte{ + byte(r >> 16), + byte(g >> 16), + byte(b >> 16), + byte(a >> 16)}) +} + +func SHA1Image(img image.Image) []byte { + + switch i := img.(type) { + case *image.RGBA: + return sha1rgba(i) + case *image.Uniform: + return sha1uniform(i) + } + + log.Println("WARN: slow path for SHA1Image") + + hash := sha1.New() + bounds := img.Bounds() + var pix [4]byte + for x := bounds.Min.X; x <= bounds.Max.X; x++ { + for y := bounds.Min.Y; y <= bounds.Max.Y; y++ { + r, g, b, a := img.At(x, y).RGBA() + pix[0] = byte(r >> 16) + pix[1] = byte(g >> 16) + pix[2] = byte(b >> 16) + pix[3] = byte(a >> 16) + hash.Write(pix[:]) + } + } + return hash.Sum(nil) +}