Skip to content

Instantly share code, notes, and snippets.

@sausheong
Created December 28, 2019 12:51
Show Gist options
  • Select an option

  • Save sausheong/f641d6c4858dfd36f7f0758241231de3 to your computer and use it in GitHub Desktop.

Select an option

Save sausheong/f641d6c4858dfd36f7f0758241231de3 to your computer and use it in GitHub Desktop.
photo mosaic blog 7
package main
import (
"fmt"
"html/template"
"net/http"
"bytes"
"encoding/base64"
"image"
"image/draw"
"image/jpeg"
"os"
"strconv"
)
func main() {
mux := http.NewServeMux()
files := http.FileServer(http.Dir("public"))
mux.Handle("/static/", http.StripPrefix("/static/", files))
mux.HandleFunc("/", upload)
mux.HandleFunc("/mosaic ", mosaic)
server := &http.Server{
Addr: "127.0.0.1:8080",
Handler: mux,
}
// building up the source tile database
TILESDB = tilesDB()
fmt.Println("Mosaic server started.")
server.ListenAndServe()
}
// to display the upload page
func upload(w http.ResponseWriter, r *http.Request) {
t, _ := template.ParseFiles("upload.html")
t.Execute(w, nil)
}
// the HandlerFunc that contains all the photo mosaic generating algorithms
func mosaic(w http.ResponseWriter, r *http.Request) {
t0 := time.Now()
// get the content from the POSTed form
r.ParseMultipartForm(10485760) // max body in memory is 10MB
file, _, _ := r.FormFile("image")
defer file.Close()
tileSize, _ := strconv.Atoi(r.FormValue("tile_size"))
// decode and get original image
original, _, _ := image.Decode(file)
bounds := original.Bounds()
// create a new image for the mosaic
newimage := image.NewNRGBA(image.Rect(bounds.Min.X, bounds.Min.X, bounds.Max.X, bounds.Max.Y))
// build up the tiles database
db := cloneTilesDB()
// source point for each tile, which starts with 0, 0 of each tile
sp := image.Point{0, 0}
for y := bounds.Min.Y; y < bounds.Max.Y; y = y + tileSize {
for x := bounds.Min.X; x < bounds.Max.X; x = x + tileSize {
// use the top left most pixel as the average color
r, g, b, _ := original.At(x, y).RGBA()
color := [3]float64{float64(r), float64(g), float64(b)}
// get the closest tile from the tiles DB
nearest := nearest(color, &db)
file, err := os.Open(nearest)
if err == nil {
img, _, err := image.Decode(file)
if err == nil {
// resize the tile to the correct size
t := resize(img, tileSize)
tile := t.SubImage(t.Bounds())
tileBounds := image.Rect(x, y, x+tileSize, y+tileSize)
// draw the tile into the mosaic
draw.Draw(newimage, tileBounds, tile, sp, draw.Src)
} else {
fmt.Println("error:", err, nearest)
}
} else {
fmt.Println("error:", nearest)
}
file.Close()
}
}
buf1 := new(bytes.Buffer)
jpeg.Encode(buf1, original, nil)
originalStr := base64.StdEncoding.EncodeToString(buf1.Bytes())
buf2 := new(bytes.Buffer)
jpeg.Encode(buf2, newimage, nil)
mosaic := base64.StdEncoding.EncodeToString(buf2.Bytes())
t1 := time.Now()
images := map[string]string{
"original": originalStr,
"mosaic": mosaic,
"duration": fmt.Sprintf("%v ", t1.Sub(t0)),
}
t, _ := template.ParseFiles("results.html")
t.Execute(w, images)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment