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
| // 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} |
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
| 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 color 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) |
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
| 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, |
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
| <!DOCTYPE html> | |
| <html> | |
| <head> | |
| <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> | |
| <title>Mosaic</title> | |
| ... | |
| </head> | |
| <body> | |
| <div class='container'> | |
| <div class="col-md-6"> |
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
| func mosaic(w http.ResponseWriter, r *http.Request) { | |
| t0 := time.Now() | |
| r.ParseMultipartForm(10485760) // max body in memory is 10MB | |
| file, _, _ := r.FormFile("image") | |
| defer file.Close() | |
| tileSize, _ := strconv.Atoi(r.FormValue("tile_size")) | |
| original, _, _ := image.Decode(file) | |
| bounds := original.Bounds() | |
| db := cloneTilesDB() | |
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
| c1 := cut(original, &db, tileSize, bounds.Min.X, bounds.Min.Y, bounds.Max.X/2, bounds.Max.Y/2) | |
| c2 := cut(original, &db, tileSize, bounds.Max.X/2, bounds.Min.Y, bounds.Max.X, bounds.Max.Y/2) | |
| c3 := cut(original, &db, tileSize, bounds.Min.X, bounds.Max.Y/2, bounds.Max.X/2, bounds.Max.Y) | |
| c4 := cut(original, &db, tileSize, bounds.Max.X/2, bounds.Max.Y/2, bounds.Max.X, bounds.Max.Y) |
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
| func cut(original image.Image, db *map[string][3]float64, tileSize, x1, y1, x2, y2 int) <-chan image.Image { | |
| c := make(chan image.Image) | |
| sp := image.Point{0, 0} | |
| go func() { | |
| newimage := image.NewNRGBA(image.Rect(x1, y1, x2, y2)) | |
| for y := y1; y < y2; y = y + tileSize { | |
| for x := x1; x < x2; x = x + tileSize { | |
| r, g, b, _ := original.At(x, y).RGBA() | |
| color := [3]float64{float64(r), float64(g), float64(b)} | |
| nearest := nearest(color, db) |
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
| func combine(r image.Rectangle, c1, c2, c3, c4 <-chan image.Image) | |
| <-chan string { | |
| c := make(chan string) | |
| // start a goroutine | |
| go func() { | |
| var wg sync.WaitGroup | |
| img:= image.NewNRGBA(r) | |
| copy := func(dst draw.Image, r image.Rectangle, | |
| src image.Image, sp image.Point) { | |
| draw.Draw(dst, r, src, sp, draw.Src) |
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
| var s1, s2, s3, s4 image.Image | |
| var ok1, ok2, ok3, ok4 bool | |
| for { | |
| select { | |
| case s1, ok1 = <-c1: | |
| go copy(img, s1.Bounds(), s1, image.Point{r.Min.X, r.Min.Y}) | |
| case s2, ok2 = <-c2: | |
| go copy(img, s2.Bounds(), s2, image.Point{r.Max.X / 2, r.Min.Y}) | |
| case s3, ok3 = <-c3: | |
| go copy(img, s3.Bounds(), s3, image.Point{r.Min.X, r.Max.Y / 2}) |
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
| func main() { | |
| // this prints out the number of CPUs in my system | |
| fmt.Println("Number of CPUs:", runtime.NumCPU()) | |
| runtime.GOMAXPROCS(runtime.NumCPU()) | |
| fmt.Println("Starting mosaic server ...") | |
| mux := http.NewServeMux() | |
| files := http.FileServer(http.Dir("public")) | |
| mux.Handle("/static/", http.StripPrefix("/static/", files)) | |
| mux.HandleFunc("/", upload) | |
| mux.HandleFunc("/mosaic", mosaic) |