Created
December 28, 2019 12:51
-
-
Save sausheong/f641d6c4858dfd36f7f0758241231de3 to your computer and use it in GitHub Desktop.
photo mosaic blog 7
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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