diff options
| author | Daniel Byron <=> | 2015-07-20 14:13:18 +1000 |
|---|---|---|
| committer | Daniel Byron <=> | 2015-07-20 14:13:18 +1000 |
| commit | ed38e7eb0f81267c6e2b520777b8b84705a3cac3 (patch) | |
| tree | 3157c55f49988e16ab2b12b07af910990ebd4097 | |
| parent | Updated readme (diff) | |
| download | schemer2-ed38e7eb0f81267c6e2b520777b8b84705a3cac3.tar.xz schemer2-ed38e7eb0f81267c6e2b520777b8b84705a3cac3.zip | |
Expose advanced image options
Includes a major rewrite of how images are generated, and makes use of
many more command line flags. Still needs much testing, however
preliminary results look good.
| -rw-r--r-- | image.go | 226 | ||||
| -rw-r--r-- | main.go | 77 |
2 files changed, 182 insertions, 121 deletions
@@ -10,9 +10,12 @@ import ( "math" "math/rand" "os" + "sort" "time" ) +var imageOutTypes = [...]string{"random", "circles", "rays", "stripes"} + func loadImage(filepath string) image.Image { infile, err := os.Open(filepath) if err != nil { @@ -34,6 +37,17 @@ func abs(n int) int { return -n } +func randMinMax(min int, max int) int { + if min == max { + return min + } + return rand.Intn(max-min) + min +} + +func randBool() bool { + return rand.Intn(2) == 0 +} + func colorDifference(col1 color.Color, col2 color.Color, threshold int) bool { c1 := col1.(color.NRGBA) c2 := col2.(color.NRGBA) @@ -101,47 +115,20 @@ func colorsFromImage(filename string) ([]color.Color, error) { return distinctColors, nil } -func imageFromColors(colors []color.Color, w int, h int) image.Image { +func imageFromColors(colors []color.Color, w int, h int) (image.Image, error) { rand.Seed(time.Now().UnixNano()) - switch rand.Intn(4) { - case 0: - // Circles - switch rand.Intn(2) { - case 0: - return Circles(colors, w, h, false) - case 1: - return Circles(colors, w, h, true) - } - case 1: - // Rays - switch rand.Intn(2) { - case 0: - return Rays(colors, w, h, true, rand.Intn(w/24)) - case 1: - return Rays(colors, w, h, false, rand.Intn(w/24)) - } - case 2: - // Horizontal Lines - switch rand.Intn(2) { - case 0: - return HorizontalLines(colors, w, h, false) - case 1: - return HorizontalLines(colors, w, h, true) - } - case 3: - // Vertical Lines - switch rand.Intn(4) { - case 0: - return VerticalLines(colors, w, h, false, false) - case 1: - return VerticalLines(colors, w, h, true, false) - case 2: - return VerticalLines(colors, w, h, false, true) - case 3: - return VerticalLines(colors, w, h, true, true) - } + switch *imageOutType { + case "random": + return randomImage(colors, w, h), nil + case "circles": + return Circles(colors, w, h, *circleSize, *circleSizeVariance, *circleOverlap, *circleDrawLargestToSmallest, *circleFilled, *circleBorderSize), nil + case "rays": + return Rays(colors, w, h, *raysSize, *raysSizeVariance, *raysDistributeEvenly, *raysCentered, *raysDrawLargestToSmallest), nil + case "stripes": + return Lines(colors, w, h, *stripesSize, *stripesSizeVariance, *stripesHorizontal, *stripesEvenSpacing, *stripesSpacing, *stripesOffset), nil + } - return nil + return nil, errors.New("Unrecognised ouput image type: " + *imageOutType + "\n") } type Circle struct { @@ -150,18 +137,28 @@ type Circle struct { size int } -func Circles(colors []color.Color, w int, h int, filled bool) image.Image { +// For sorting circles by size +type circleBySize []Circle + +func (a circleBySize) Len() int { return len(a) } +func (a circleBySize) Swap(i, j int) { a[i], a[j] = a[j], a[i] } +func (a circleBySize) Less(i, j int) bool { return a[i].size < a[j].size } + +func Circles(colors []color.Color, w int, h int, size int, sizevar int, overlap bool, large2small bool, filled bool, bordersize int) image.Image { img := image.NewNRGBA(image.Rect(0, 0, w, h)) circles := make([]Circle, 0) for _, c := range colors { - circle := Circle{c, rand.Intn(w), rand.Intn(h), rand.Intn(w / 2)} + circle := Circle{c, rand.Intn(w), rand.Intn(h), randMinMax(size-sizevar, size+sizevar)} circles = append(circles, circle) } bg := colors[0] - border := rand.Intn(w / 24) + + if large2small { + sort.Sort(circleBySize(circles)) + } for x := 0; x < w; x++ { for y := 0; y < h; y++ { @@ -175,7 +172,7 @@ func Circles(colors []color.Color, w int, h int, filled bool) image.Image { img.Set(x, y, c.col) } } else { - if int(math.Sqrt(a+b)) < c.size && int(math.Sqrt(a+b)) > (c.size-border) { + if int(math.Sqrt(a+b)) < c.size && int(math.Sqrt(a+b)) > (c.size-bordersize) { img.Set(x, y, c.col) } } @@ -185,80 +182,46 @@ func Circles(colors []color.Color, w int, h int, filled bool) image.Image { return img } -type Stripe struct { +type Ray struct { col color.Color x, y int // Middle point angle int // 0-180 + size int } -func Rays(colors []color.Color, w int, h int, centered bool, margin int) image.Image { - img := image.NewNRGBA(image.Rect(0, 0, w, h)) - - stripes := make([]Stripe, 0) - - for _, c := range colors { - var stripe Stripe - if centered { - stripe = Stripe{c, w / 2, h / 2, rand.Intn(180)} - } else { - stripe = Stripe{c, rand.Intn(w), rand.Intn(h), rand.Intn(180)} - } - stripes = append(stripes, stripe) - } - - bg := colors[0] - - for x := 0; x < w; x++ { - for y := 0; y < h; y++ { - img.Set(x, y, bg) - for _, s := range stripes { - deltaX := float64(x - s.x) - deltaY := float64(y - s.y) - angle := math.Atan(deltaY/deltaX) * 180 / math.Pi - if int(math.Abs(float64(int(angle)-s.angle))) < margin { - img.Set(x, y, s.col) - } - } - } - } - return img -} - -type VerticalLine struct { - col color.Color - x int - w int -} +// For sorting rays by size +type rayBySize []Ray -type HorizontalLine struct { - col color.Color - y int - h int -} +func (a rayBySize) Len() int { return len(a) } +func (a rayBySize) Swap(i, j int) { a[i], a[j] = a[j], a[i] } +func (a rayBySize) Less(i, j int) bool { return a[i].size < a[j].size } -func VerticalLines(colors []color.Color, w int, h int, evenlySpaced bool, evenWidth bool) image.Image { +func Rays(colors []color.Color, w int, h int, size int, sizevar int, evendist bool, centered bool, large2small bool) image.Image { img := image.NewNRGBA(image.Rect(0, 0, w, h)) - lines := make([]VerticalLine, 0) - - var width int - width = rand.Intn(w / 16) + rays := make([]Ray, 0) - x_index := rand.Intn(w / 2) + spacing := 180 / len(colors) + current_angle := 0 - var spacing int - spacing = rand.Intn(w / 32) + xpos := w / 2 + ypos := h / 2 for _, c := range colors { - if !evenWidth { - width = rand.Intn(w / 16) + var ray Ray + if !centered { + xpos = rand.Intn(w) + ypos = rand.Intn(h) } - if !evenlySpaced { - spacing = rand.Intn(w / 32) + if !evendist { + current_angle = rand.Intn(180) } - x_index += spacing - lines = append(lines, VerticalLine{c, x_index, width}) - x_index += width + ray = Ray{c, xpos, ypos, current_angle, randMinMax(size-sizevar, size+sizevar)} + + if evendist { + current_angle += spacing + ray.size + } + rays = append(rays, ray) } bg := colors[0] @@ -266,33 +229,46 @@ func VerticalLines(colors []color.Color, w int, h int, evenlySpaced bool, evenWi for x := 0; x < w; x++ { for y := 0; y < h; y++ { img.Set(x, y, bg) - for _, l := range lines { - if x >= l.x && x < l.x+l.w { - img.Set(x, y, l.col) + for _, r := range rays { + deltaX := float64(x - r.x) + deltaY := float64(y - r.y) + angle := math.Atan(deltaY/deltaX) * 180 / math.Pi + if int(math.Abs(float64(int(angle)-r.angle))) < r.size { + img.Set(x, y, r.col) } } } } - return img +} +type Line struct { + col color.Color + position int + size int } -func HorizontalLines(colors []color.Color, w int, h int, evenHeight bool) image.Image { +func Lines(colors []color.Color, w int, h int, size int, sizevar int, horizontal bool, equalspacing bool, spacingsize int, offset int) image.Image { img := image.NewNRGBA(image.Rect(0, 0, w, h)) + var maxsize int + if horizontal { + maxsize = h + } else { + maxsize = w + } - lines := make([]HorizontalLine, 0) + currentposition := offset + spacing := spacingsize - var height int - if evenHeight { - height = rand.Intn(h / 16) - } + lines := make([]Line, 0) for _, c := range colors { - if !evenHeight { - height = rand.Intn(h / 16) + line := Line{c, currentposition, randMinMax(size-sizevar, size+sizevar)} + lines = append(lines, line) + if !equalspacing { + spacing = rand.Intn(maxsize / 16) } - lines = append(lines, HorizontalLine{c, rand.Intn(h), height}) + currentposition += line.size + spacing } bg := colors[0] @@ -301,7 +277,14 @@ func HorizontalLines(colors []color.Color, w int, h int, evenHeight bool) image. for y := 0; y < h; y++ { img.Set(x, y, bg) for _, l := range lines { - if y >= l.y && y < l.y+l.h { + var pixelpos int + if horizontal { + pixelpos = y + } else { + pixelpos = x + } + + if pixelpos > l.position && pixelpos < l.position+l.size { img.Set(x, y, l.col) } } @@ -309,5 +292,16 @@ func HorizontalLines(colors []color.Color, w int, h int, evenHeight bool) image. } return img +} +func randomImage(colors []color.Color, w int, h int) image.Image { + switch rand.Intn(3) { + case 0: + return Circles(colors, w, h, rand.Intn(w/2), rand.Intn(w/2), randBool(), randBool(), randBool(), rand.Intn(w/16)) + case 1: + return Rays(colors, w, h, rand.Intn(h/32), rand.Intn(h/32), randBool(), true, randBool()) + case 2: + return Lines(colors, w, h, rand.Intn(h/32), rand.Intn(h/32), randBool(), randBool(), rand.Intn(h/32), rand.Intn(h/2)) + } + return nil } @@ -15,15 +15,45 @@ const ( ) var ( - threshold *int outfile *string infile *string format_string *string + + // Image input options + threshold *int minBrightness *int maxBrightness *int - imageWidth *int - imageHeight *int + // Generic image output options + imageWidth *int + imageHeight *int + imageOutType *string // Eg, "random", "circles", "stripes", etc... + + // Circles image output options + circleSize *int + circleSizeVariance *int + circleOverlap *bool + circleDrawLargestToSmallest *bool + circleFilled *bool + circleBorderSize *int + + // Ray image output options + raysSize *int + raysSizeVariance *int + raysDistributeEvenly *bool + raysCentered *bool + raysDrawLargestToSmallest *bool + + // Stripes image output options + stripesSize *int + stripesSizeVariance *int + stripesHorizontal *bool + stripesEqualSize *bool + stripesEvenSpacing *bool + stripesSpacing *int + stripesOffset *int + + // Show advanced help advancedoptions *bool ) @@ -63,14 +93,47 @@ func inputs_outputs() { } func main() { - threshold = flag.Int("threshold", 50, "Threshold for minimum color difference (image input only)") infile = flag.String("in", "", "Input file") outfile = flag.String("out", "", "File to write output to.") format_string = flag.String("format", "", "Format of input and output. Eg. 'image"+format_separator+"xterm'") + + threshold = flag.Int("threshold", 50, "Threshold for minimum color difference (image input only)") minBrightness = flag.Int("minBright", 0, "Minimum brightness for colors (image input only)") maxBrightness = flag.Int("maxBright", 200, "Maximum brightness for colors (image input only)") + imageHeight = flag.Int("height", 1080, "Height of output image") imageWidth = flag.Int("width", 1920, "Width of output image") + imageOutTypeDesc := "Type of image to generate. Available options: \n" + for _, t := range imageOutTypes { + imageOutTypeDesc += " " + imageOutTypeDesc += t + imageOutTypeDesc += "\n" + } + imageOutType = flag.String("imageOutType", "random", imageOutTypeDesc) + + // Circles image output options + circleSize = flag.Int("circleSize", 100, "Size of circles in output image") + circleSizeVariance = flag.Int("circleSizeVariance", 50, "Maximum variance in circle size") + circleOverlap = flag.Bool("circleOverlap", true, "Allow circles to overlap !!! Unimplemented !!!") + circleDrawLargestToSmallest = flag.Bool("circleLargeToSmall", true, "Order circles z-index by size (smaller circles are drawn in front of larger circles)") + circleFilled = flag.Bool("circleFilled", false, "Fill circles") + circleBorderSize = flag.Int("circleBorderSize", 10, "Border of circles when unfilled") + + // Ray image output options + raysSize = flag.Int("raysSize", 16, "Size of rays in output image") + raysSizeVariance = flag.Int("raysSizeVariance", 8, "Maximum variance in rays size") + raysDistributeEvenly = flag.Bool("raysDistributeEvenly", false, "Distribute rays evenly") + raysCentered = flag.Bool("raysCentered", true, "Center rays in middle") + raysDrawLargestToSmallest = flag.Bool("raysLargeToSmall", false, "Order rays z-index by size (smaller rays are drawn on top of larger rays)") + + // Stripes image output options + stripesSize = flag.Int("stripesSize", 6, "Size of stripes in output image") + stripesSizeVariance = flag.Int("stripesSizeVariance", 3, "Maximum variance in stripes size") + stripesHorizontal = flag.Bool("stripesHorizontal", false, "Draw stripes horizontally instead of vertically") + stripesEvenSpacing = flag.Bool("stripesEvenSpacing", true, "Space all stripes evenly") + stripesSpacing = flag.Int("stripesSpacing", 0, "Space stripes by this amount when spacing evenly") + stripesOffset = flag.Int("stripesOffset", 0, "Offset stripes by this amount") + advancedoptions = flag.Bool("help-advanced", false, "Show advanced command line options") flag.Usage = flags_usage @@ -196,7 +259,11 @@ func main() { } defer file.Close() - img := imageFromColors(colors, *imageWidth, *imageHeight) // TODO + img, err := imageFromColors(colors, *imageWidth, *imageHeight) // TODO + if err != nil { + fmt.Printf(err.Error()) + os.Exit(1) + } png.Encode(file, img) } |