// ValidateImgParams validates desired output image parameters. func ValidateImgParams(imgP *ImgParams) error { if imgP.Width%constants.TileSize != 0 || imgP.Height%constants.TileSize != 0 { return fmt.Errorf("width(%d) and height(%d) of the resulting picture"+ " should be multiples of tile size(%d)\n", imgP.Width, imgP.Height, constants.TileSize) } ratioXY := float64(constants.YMax-constants.YMin) / float64(constants.XMax-constants.XMin) ratioPxPy := float64(imgP.Height) / float64(imgP.Width) if ratioXY != ratioPxPy { sugestedWidth := int(float64(imgP.Height) / ratioXY) msgFmt := "pixel ratio (%2.2f) differs from XY ratio(%2.2f), try" + " adjusting width to %d\n\n" return fmt.Errorf(msgFmt, ratioPxPy, ratioXY, sugestedWidth) } if imgP.Scaling < 1 { msgFmt := "scaling factor must be >= 1, currently: `%d`\n" return fmt.Errorf(msgFmt, imgP.Scaling) } if _, err := algos.MapStr2Func(imgP.Algo); err != nil { return err } return nil }
// BuildImg coordinates tasks between individual tile-processors. It does not // directly write pixels, only sends tile numbers to calculate to processors. func BuildImg(imgP *cmdline.ImgParams) *image.RGBA { f, _ := algos.MapStr2Func(imgP.Algo) img := image.NewRGBA(image.Rect(0, 0, imgP.Width, imgP.Height)) waitGroup, workerCh := spawnProcessors(imgP.Scaling, img, f) for py := 0; py < imgP.Height; py += constants.TileSize { for px := 0; px < imgP.Width; px += constants.TileSize { // (sur) should I worry about generating to many objects for GC ? workerCh <- [2]int{py, px} } } close(workerCh) waitGroup.Wait() return img }