func getScaledTile(x, y int, scale float64) (scaledTile image.Image, ok bool) { unscaled, ok := getTile(x, y) if !ok { return } stiles, ok := scaledTiles[scale] if !ok { stiles = map[int]map[int]chan image.Image{} scaledTiles[scale] = stiles } sxtiles, ok := stiles[x] if !ok { sxtiles = map[int]chan image.Image{} stiles[x] = sxtiles } scaledTileChan, ok := sxtiles[y] if !ok { bounds := unscaled.Bounds() s := bounds.Size() scaledTileChan = make(chan image.Image, 1) go func() { scaledTileChan <- resize.Resize(unscaled, unscaled.Bounds(), int(.5+float64(s.X)/scale), int(.5+float64(s.Y)/scale)) }() sxtiles[y] = scaledTileChan } select { case scaledTile = <-scaledTileChan: scaledTileChan <- scaledTile default: ok = false } return }
func Index() error { // Just a hardcoded path obviously needs to scan directory. file, err := os.Open("photos/IMG_0128.JPG") if err != nil { return err } img, err := jpeg.Decode(file) if err != nil { return err } file.Close() ratio := 500.0 / float32(img.Bounds().Max.X) new_height := int(ratio * float32(img.Bounds().Max.Y)) resized := resize.Resize(img, img.Bounds(), 500, new_height) file, err = os.Create("photos/IMG_0128_THUMB.JPG") if err != nil { return err } jpeg.Encode(file, resized, &jpeg.Options{Quality: 100}) file.Close() return nil }
func window() { var wg sync.WaitGroup size := 500 wg.Add(1) go func() { dw, err := wde.NewWindow(size, size) if err != nil { fmt.Println(err) return } dw.SetTitle("xkcd-zoom") dw.SetSize(size, size) dw.Show() events := dw.EventChan() const ( Draw = 1 Redraw = 2 ScaleInPlace = 3 ) redraw := make(chan int, 1) redraw <- Draw done := make(chan bool) go func() { for { time.Sleep(time.Second) redraw <- Redraw } }() go func() { loop: for ei := range events { redrawType := 0 runtime.Gosched() switch e := ei.(type) { case wde.MouseDownEvent: case wde.MouseDraggedEvent: switch e.Which { case wde.LeftButton: changedx := e.Where.X - e.From.X changedy := e.Where.Y - e.From.Y drawx += float64(changedx) * scale drawy += float64(-changedy) * scale redrawType = Draw case wde.RightButton: changedy := e.From.Y - e.Where.Y mouseScale := float64(changedy) / 100 scale *= math.Pow(2, mouseScale) redrawType = ScaleInPlace } case wde.MouseUpEvent: if e.Which == wde.RightButton { scaledTiles = map[float64]map[int]map[int]chan image.Image{} redrawType = Draw } case wde.KeyTypedEvent: if e.Key == wde.KeyEscape { break loop } case wde.CloseEvent: break loop case wde.ResizeEvent: redrawType = Draw } if redrawType != 0 { select { case redraw <- redrawType: default: } } } dw.Close() done <- true }() var greyBack, screenBuffer *image.RGBA var grey = color.RGBA{155, 155, 155, 255} var bufferScale = scale var lastRedraw int for { select { case redrawType := <-redraw: if lastRedraw == ScaleInPlace && redrawType == Redraw { continue } lastRedraw = redrawType s := dw.Screen() if redrawType == Draw || redrawType == Redraw { width, height := dw.Size() tilesh := int(float64(width)/(float64(imageWidth)/scale) + 1) tilesv := int(float64(height)/(float64(imageHeight)/scale) + 1) tilecx := drawx / imageWidth tilecy := drawy / imageHeight tileMinX := int(-tilecx) - tilesh - 1 tileMinY := int(-tilecy) - tilesv - 1 tileMaxX := int(-tilecx) + tilesh + 1 tileMaxY := int(-tilecy) + tilesv + 1 if greyBack == nil || s.Bounds() != greyBack.Bounds() { bounds := s.Bounds() greyBack = image.NewRGBA(bounds) for x := bounds.Min.X; x <= bounds.Max.X; x++ { for y := bounds.Min.Y; y <= bounds.Max.Y; y++ { greyBack.SetRGBA(x, y, grey) } } screenBuffer = image.NewRGBA(bounds) } draw.Draw(screenBuffer, screenBuffer.Bounds(), greyBack, image.Point{0, 0}, draw.Src) for tilex := tileMinX; tilex <= tileMaxX; tilex++ { for tiley := tileMinY; tiley <= tileMaxY; tiley++ { scaledTile, ok := getScaledTile(tilex, tiley, scale) if !ok || scaledTile == nil { continue } dx, dy := mapToScreen(width, height, float64(tilex)*imageWidth, float64(tiley)*imageHeight) drawRect := scaledTile.Bounds() drawRect.Min.X += dx drawRect.Min.Y -= dy drawRect.Max.X += dx drawRect.Max.Y -= dy draw.Draw(screenBuffer, drawRect, scaledTile, image.Point{0, 0}, draw.Src) } } bufferScale = scale if xs, ok := s.(*xgraphics.Image); ok { copyToXGraphicsImage(xs, screenBuffer) } else { draw.Draw(s, s.Bounds(), screenBuffer, image.Point{0, 0}, draw.Src) } } else if redrawType == ScaleInPlace { scaleFactor := scale / bufferScale bufBounds := screenBuffer.Bounds() width := bufBounds.Max.X - bufBounds.Min.X height := bufBounds.Max.Y - bufBounds.Min.Y if scaleFactor < 1 { widthDiff := width - int(float64(width)*scaleFactor) heightDiff := height - int(float64(height)*scaleFactor) //bufBounds.Min.X += widthDiff / 2 bufBounds.Max.X -= widthDiff //bufBounds.Min.Y += heightDiff / 2 bufBounds.Max.Y -= heightDiff subBuffer := screenBuffer.SubImage(bufBounds) scaledBuffer := resize.Resize(subBuffer, subBuffer.Bounds(), width, height).(*image.RGBA) if xs, ok := s.(*xgraphics.Image); ok { copyToXGraphicsImage(xs, scaledBuffer) } else { draw.Draw(s, s.Bounds(), scaledBuffer, image.Point{0, 0}, draw.Src) } } if scaleFactor > 1 { scaleFactor = 1 / scaleFactor newWidth := int(float64(width) * scaleFactor) newHeight := int(float64(height) * scaleFactor) scaledBuffer := resize.Resize(screenBuffer, screenBuffer.Bounds(), newWidth, newHeight).(*image.RGBA) if xs, ok := s.(*xgraphics.Image); ok { copyToXGraphicsImage(xs, scaledBuffer) } else { draw.Draw(s, s.Bounds(), scaledBuffer, image.Point{0, 0}, draw.Src) } } } dw.FlushImage() case <-done: wg.Done() return } } }() wg.Wait() wde.Stop() }