Generating Image & Serving via HTTP with Go












1














What is does



I'm reading The Go Programming Language. Below is my code for the last exercise in the first chapter, which is to create a webserver, generate an image, and serve the image via the server, allowing modifications of the image via query string parameters, eg: localhost:8000/?cycles=25&bgcolor=0,255,255.



My Concerns



I'm open to any and all suggestions, but any advice specifically concerning these points would be especially helpful.



Duplicated code. There's just enough duplication to trigger my OCD, but each one is slightly different so I'm not sure how I could delegate to a function without creating a bunch of very similar functions. In particular, the two for loops where I'm parsing colors really bother me.



Type Juggling. strconv.ParseInt has a third argument to specify the bit size but always returns int64 anyway, so I still have to explicitly cast then to unsigned 8 bit integers. Take a look at my img.SetColorIndex call where I'm doing all sorts of casting just for some simple arithmetic.



Concision. I am baffled at the fact that I can write a simple server using the standard library with about 4 lines of code, but turning a string into an array of numbers took me 19 lines of code. And I had to use basically the same 19 lines twice because I couldn't figure out what to specify as the type when passing a color.RGBA as a function parameter.



package main

import (
"log"
"net/http"
"io"

"image"
"image/color"
"image/gif"
"math"
"math/rand"

"strconv"
"strings"
)

var bgcolor = color.RGBA{0, 0, 0, 255}
var fgcolor = color.RGBA{255, 255, 255, 255}

func main() {
http.HandleFunc("/", serveImage)
log.Fatal(http.ListenAndServe("localhost:8000", nil))
}

func serveImage(w http.ResponseWriter, r* http.Request) {
if err := r.ParseForm(); err != nil {
log.Print(err)
}
cycles := 10.0
res := 0.001
size := 100
frames := 64
delay := 8
if value, exists := r.Form["cycles"]; exists {
if v, err := strconv.ParseFloat(value[0], 64); err == nil {
cycles = v
}
}
if value, exists := r.Form["res"]; exists {
if v, err := strconv.ParseFloat(value[0], 64); err == nil {
res = v
}
}
if value, exists := r.Form["size"]; exists {
if v, err := strconv.ParseFloat(value[0], 64); err == nil {
size = int((v-1)/2)
}
}
if value, exists := r.Form["frames"]; exists {
if v, err := strconv.ParseInt(value[0], 10, 0); err == nil {
frames = int(v)
}
}
if value, exists := r.Form["delay"]; exists {
if v, err := strconv.ParseInt(value[0], 10, 0); err == nil {
delay = int(v)
}
}
if value, exists := r.Form["bgcolor"]; exists {
BGColorLoop:
for {
parts := strings.Split(value[0], ",")
if len(parts) != 3 {
break BGColorLoop
}
for _, val := range parts {
if v, err := strconv.ParseInt(val, 10, 0); err != nil || int(v) > 255 || int(v) < 0 {
break BGColorLoop
}
}
r, _ := strconv.ParseInt(parts[0], 10, 8)
g, _ := strconv.ParseInt(parts[1], 10, 8)
b, _ := strconv.ParseInt(parts[2], 10, 8)
bgcolor = color.RGBA{uint8(r), uint8(g), uint8(b), 255}
break BGColorLoop
}
}
if value, exists := r.Form["fgcolor"]; exists {
FGColorLoop:
for {
parts := strings.Split(value[0], ",")
if len(parts) != 3 {
break FGColorLoop
}
for _, val := range parts {
if v, err := strconv.ParseInt(val, 10, 0); err != nil || int(v) > 255 || int(v) < 0 {
break FGColorLoop
}
}
r, _ := strconv.ParseInt(parts[0], 10, 8)
g, _ := strconv.ParseInt(parts[1], 10, 8)
b, _ := strconv.ParseInt(parts[2], 10, 8)
fgcolor = color.RGBA{uint8(r), uint8(g), uint8(b), 255}
break FGColorLoop
}
}
lissajous(w, cycles, res, size, frames, delay)
}

func lissajous(out io.Writer, cycles float64, res float64, size int, nframes int, delay int) {
freq := rand.Float64() * 3.0
anim := gif.GIF{LoopCount: nframes}
phase := 0.0
palette := color.Color{bgcolor, fgcolor}
for i := 0; i<nframes; i++ {
rect := image.Rect(0, 0, 2*size+1, 2*size+1)
img := image.NewPaletted(rect, palette)
for t:=0.0; t<cycles*2*math.Pi; t+=res {
x := math.Sin(t)
y := math.Sin(t*freq+phase)
img.SetColorIndex(size+int(x*float64(size)+0.5), size+int(y*float64(size)+0.5), 1)
}
phase += 0.1
anim.Delay = append(anim.Delay, delay)
anim.Image = append(anim.Image, img)
}
gif.EncodeAll(out, &anim)
}









share|improve this question



























    1














    What is does



    I'm reading The Go Programming Language. Below is my code for the last exercise in the first chapter, which is to create a webserver, generate an image, and serve the image via the server, allowing modifications of the image via query string parameters, eg: localhost:8000/?cycles=25&bgcolor=0,255,255.



    My Concerns



    I'm open to any and all suggestions, but any advice specifically concerning these points would be especially helpful.



    Duplicated code. There's just enough duplication to trigger my OCD, but each one is slightly different so I'm not sure how I could delegate to a function without creating a bunch of very similar functions. In particular, the two for loops where I'm parsing colors really bother me.



    Type Juggling. strconv.ParseInt has a third argument to specify the bit size but always returns int64 anyway, so I still have to explicitly cast then to unsigned 8 bit integers. Take a look at my img.SetColorIndex call where I'm doing all sorts of casting just for some simple arithmetic.



    Concision. I am baffled at the fact that I can write a simple server using the standard library with about 4 lines of code, but turning a string into an array of numbers took me 19 lines of code. And I had to use basically the same 19 lines twice because I couldn't figure out what to specify as the type when passing a color.RGBA as a function parameter.



    package main

    import (
    "log"
    "net/http"
    "io"

    "image"
    "image/color"
    "image/gif"
    "math"
    "math/rand"

    "strconv"
    "strings"
    )

    var bgcolor = color.RGBA{0, 0, 0, 255}
    var fgcolor = color.RGBA{255, 255, 255, 255}

    func main() {
    http.HandleFunc("/", serveImage)
    log.Fatal(http.ListenAndServe("localhost:8000", nil))
    }

    func serveImage(w http.ResponseWriter, r* http.Request) {
    if err := r.ParseForm(); err != nil {
    log.Print(err)
    }
    cycles := 10.0
    res := 0.001
    size := 100
    frames := 64
    delay := 8
    if value, exists := r.Form["cycles"]; exists {
    if v, err := strconv.ParseFloat(value[0], 64); err == nil {
    cycles = v
    }
    }
    if value, exists := r.Form["res"]; exists {
    if v, err := strconv.ParseFloat(value[0], 64); err == nil {
    res = v
    }
    }
    if value, exists := r.Form["size"]; exists {
    if v, err := strconv.ParseFloat(value[0], 64); err == nil {
    size = int((v-1)/2)
    }
    }
    if value, exists := r.Form["frames"]; exists {
    if v, err := strconv.ParseInt(value[0], 10, 0); err == nil {
    frames = int(v)
    }
    }
    if value, exists := r.Form["delay"]; exists {
    if v, err := strconv.ParseInt(value[0], 10, 0); err == nil {
    delay = int(v)
    }
    }
    if value, exists := r.Form["bgcolor"]; exists {
    BGColorLoop:
    for {
    parts := strings.Split(value[0], ",")
    if len(parts) != 3 {
    break BGColorLoop
    }
    for _, val := range parts {
    if v, err := strconv.ParseInt(val, 10, 0); err != nil || int(v) > 255 || int(v) < 0 {
    break BGColorLoop
    }
    }
    r, _ := strconv.ParseInt(parts[0], 10, 8)
    g, _ := strconv.ParseInt(parts[1], 10, 8)
    b, _ := strconv.ParseInt(parts[2], 10, 8)
    bgcolor = color.RGBA{uint8(r), uint8(g), uint8(b), 255}
    break BGColorLoop
    }
    }
    if value, exists := r.Form["fgcolor"]; exists {
    FGColorLoop:
    for {
    parts := strings.Split(value[0], ",")
    if len(parts) != 3 {
    break FGColorLoop
    }
    for _, val := range parts {
    if v, err := strconv.ParseInt(val, 10, 0); err != nil || int(v) > 255 || int(v) < 0 {
    break FGColorLoop
    }
    }
    r, _ := strconv.ParseInt(parts[0], 10, 8)
    g, _ := strconv.ParseInt(parts[1], 10, 8)
    b, _ := strconv.ParseInt(parts[2], 10, 8)
    fgcolor = color.RGBA{uint8(r), uint8(g), uint8(b), 255}
    break FGColorLoop
    }
    }
    lissajous(w, cycles, res, size, frames, delay)
    }

    func lissajous(out io.Writer, cycles float64, res float64, size int, nframes int, delay int) {
    freq := rand.Float64() * 3.0
    anim := gif.GIF{LoopCount: nframes}
    phase := 0.0
    palette := color.Color{bgcolor, fgcolor}
    for i := 0; i<nframes; i++ {
    rect := image.Rect(0, 0, 2*size+1, 2*size+1)
    img := image.NewPaletted(rect, palette)
    for t:=0.0; t<cycles*2*math.Pi; t+=res {
    x := math.Sin(t)
    y := math.Sin(t*freq+phase)
    img.SetColorIndex(size+int(x*float64(size)+0.5), size+int(y*float64(size)+0.5), 1)
    }
    phase += 0.1
    anim.Delay = append(anim.Delay, delay)
    anim.Image = append(anim.Image, img)
    }
    gif.EncodeAll(out, &anim)
    }









    share|improve this question

























      1












      1








      1


      1





      What is does



      I'm reading The Go Programming Language. Below is my code for the last exercise in the first chapter, which is to create a webserver, generate an image, and serve the image via the server, allowing modifications of the image via query string parameters, eg: localhost:8000/?cycles=25&bgcolor=0,255,255.



      My Concerns



      I'm open to any and all suggestions, but any advice specifically concerning these points would be especially helpful.



      Duplicated code. There's just enough duplication to trigger my OCD, but each one is slightly different so I'm not sure how I could delegate to a function without creating a bunch of very similar functions. In particular, the two for loops where I'm parsing colors really bother me.



      Type Juggling. strconv.ParseInt has a third argument to specify the bit size but always returns int64 anyway, so I still have to explicitly cast then to unsigned 8 bit integers. Take a look at my img.SetColorIndex call where I'm doing all sorts of casting just for some simple arithmetic.



      Concision. I am baffled at the fact that I can write a simple server using the standard library with about 4 lines of code, but turning a string into an array of numbers took me 19 lines of code. And I had to use basically the same 19 lines twice because I couldn't figure out what to specify as the type when passing a color.RGBA as a function parameter.



      package main

      import (
      "log"
      "net/http"
      "io"

      "image"
      "image/color"
      "image/gif"
      "math"
      "math/rand"

      "strconv"
      "strings"
      )

      var bgcolor = color.RGBA{0, 0, 0, 255}
      var fgcolor = color.RGBA{255, 255, 255, 255}

      func main() {
      http.HandleFunc("/", serveImage)
      log.Fatal(http.ListenAndServe("localhost:8000", nil))
      }

      func serveImage(w http.ResponseWriter, r* http.Request) {
      if err := r.ParseForm(); err != nil {
      log.Print(err)
      }
      cycles := 10.0
      res := 0.001
      size := 100
      frames := 64
      delay := 8
      if value, exists := r.Form["cycles"]; exists {
      if v, err := strconv.ParseFloat(value[0], 64); err == nil {
      cycles = v
      }
      }
      if value, exists := r.Form["res"]; exists {
      if v, err := strconv.ParseFloat(value[0], 64); err == nil {
      res = v
      }
      }
      if value, exists := r.Form["size"]; exists {
      if v, err := strconv.ParseFloat(value[0], 64); err == nil {
      size = int((v-1)/2)
      }
      }
      if value, exists := r.Form["frames"]; exists {
      if v, err := strconv.ParseInt(value[0], 10, 0); err == nil {
      frames = int(v)
      }
      }
      if value, exists := r.Form["delay"]; exists {
      if v, err := strconv.ParseInt(value[0], 10, 0); err == nil {
      delay = int(v)
      }
      }
      if value, exists := r.Form["bgcolor"]; exists {
      BGColorLoop:
      for {
      parts := strings.Split(value[0], ",")
      if len(parts) != 3 {
      break BGColorLoop
      }
      for _, val := range parts {
      if v, err := strconv.ParseInt(val, 10, 0); err != nil || int(v) > 255 || int(v) < 0 {
      break BGColorLoop
      }
      }
      r, _ := strconv.ParseInt(parts[0], 10, 8)
      g, _ := strconv.ParseInt(parts[1], 10, 8)
      b, _ := strconv.ParseInt(parts[2], 10, 8)
      bgcolor = color.RGBA{uint8(r), uint8(g), uint8(b), 255}
      break BGColorLoop
      }
      }
      if value, exists := r.Form["fgcolor"]; exists {
      FGColorLoop:
      for {
      parts := strings.Split(value[0], ",")
      if len(parts) != 3 {
      break FGColorLoop
      }
      for _, val := range parts {
      if v, err := strconv.ParseInt(val, 10, 0); err != nil || int(v) > 255 || int(v) < 0 {
      break FGColorLoop
      }
      }
      r, _ := strconv.ParseInt(parts[0], 10, 8)
      g, _ := strconv.ParseInt(parts[1], 10, 8)
      b, _ := strconv.ParseInt(parts[2], 10, 8)
      fgcolor = color.RGBA{uint8(r), uint8(g), uint8(b), 255}
      break FGColorLoop
      }
      }
      lissajous(w, cycles, res, size, frames, delay)
      }

      func lissajous(out io.Writer, cycles float64, res float64, size int, nframes int, delay int) {
      freq := rand.Float64() * 3.0
      anim := gif.GIF{LoopCount: nframes}
      phase := 0.0
      palette := color.Color{bgcolor, fgcolor}
      for i := 0; i<nframes; i++ {
      rect := image.Rect(0, 0, 2*size+1, 2*size+1)
      img := image.NewPaletted(rect, palette)
      for t:=0.0; t<cycles*2*math.Pi; t+=res {
      x := math.Sin(t)
      y := math.Sin(t*freq+phase)
      img.SetColorIndex(size+int(x*float64(size)+0.5), size+int(y*float64(size)+0.5), 1)
      }
      phase += 0.1
      anim.Delay = append(anim.Delay, delay)
      anim.Image = append(anim.Image, img)
      }
      gif.EncodeAll(out, &anim)
      }









      share|improve this question













      What is does



      I'm reading The Go Programming Language. Below is my code for the last exercise in the first chapter, which is to create a webserver, generate an image, and serve the image via the server, allowing modifications of the image via query string parameters, eg: localhost:8000/?cycles=25&bgcolor=0,255,255.



      My Concerns



      I'm open to any and all suggestions, but any advice specifically concerning these points would be especially helpful.



      Duplicated code. There's just enough duplication to trigger my OCD, but each one is slightly different so I'm not sure how I could delegate to a function without creating a bunch of very similar functions. In particular, the two for loops where I'm parsing colors really bother me.



      Type Juggling. strconv.ParseInt has a third argument to specify the bit size but always returns int64 anyway, so I still have to explicitly cast then to unsigned 8 bit integers. Take a look at my img.SetColorIndex call where I'm doing all sorts of casting just for some simple arithmetic.



      Concision. I am baffled at the fact that I can write a simple server using the standard library with about 4 lines of code, but turning a string into an array of numbers took me 19 lines of code. And I had to use basically the same 19 lines twice because I couldn't figure out what to specify as the type when passing a color.RGBA as a function parameter.



      package main

      import (
      "log"
      "net/http"
      "io"

      "image"
      "image/color"
      "image/gif"
      "math"
      "math/rand"

      "strconv"
      "strings"
      )

      var bgcolor = color.RGBA{0, 0, 0, 255}
      var fgcolor = color.RGBA{255, 255, 255, 255}

      func main() {
      http.HandleFunc("/", serveImage)
      log.Fatal(http.ListenAndServe("localhost:8000", nil))
      }

      func serveImage(w http.ResponseWriter, r* http.Request) {
      if err := r.ParseForm(); err != nil {
      log.Print(err)
      }
      cycles := 10.0
      res := 0.001
      size := 100
      frames := 64
      delay := 8
      if value, exists := r.Form["cycles"]; exists {
      if v, err := strconv.ParseFloat(value[0], 64); err == nil {
      cycles = v
      }
      }
      if value, exists := r.Form["res"]; exists {
      if v, err := strconv.ParseFloat(value[0], 64); err == nil {
      res = v
      }
      }
      if value, exists := r.Form["size"]; exists {
      if v, err := strconv.ParseFloat(value[0], 64); err == nil {
      size = int((v-1)/2)
      }
      }
      if value, exists := r.Form["frames"]; exists {
      if v, err := strconv.ParseInt(value[0], 10, 0); err == nil {
      frames = int(v)
      }
      }
      if value, exists := r.Form["delay"]; exists {
      if v, err := strconv.ParseInt(value[0], 10, 0); err == nil {
      delay = int(v)
      }
      }
      if value, exists := r.Form["bgcolor"]; exists {
      BGColorLoop:
      for {
      parts := strings.Split(value[0], ",")
      if len(parts) != 3 {
      break BGColorLoop
      }
      for _, val := range parts {
      if v, err := strconv.ParseInt(val, 10, 0); err != nil || int(v) > 255 || int(v) < 0 {
      break BGColorLoop
      }
      }
      r, _ := strconv.ParseInt(parts[0], 10, 8)
      g, _ := strconv.ParseInt(parts[1], 10, 8)
      b, _ := strconv.ParseInt(parts[2], 10, 8)
      bgcolor = color.RGBA{uint8(r), uint8(g), uint8(b), 255}
      break BGColorLoop
      }
      }
      if value, exists := r.Form["fgcolor"]; exists {
      FGColorLoop:
      for {
      parts := strings.Split(value[0], ",")
      if len(parts) != 3 {
      break FGColorLoop
      }
      for _, val := range parts {
      if v, err := strconv.ParseInt(val, 10, 0); err != nil || int(v) > 255 || int(v) < 0 {
      break FGColorLoop
      }
      }
      r, _ := strconv.ParseInt(parts[0], 10, 8)
      g, _ := strconv.ParseInt(parts[1], 10, 8)
      b, _ := strconv.ParseInt(parts[2], 10, 8)
      fgcolor = color.RGBA{uint8(r), uint8(g), uint8(b), 255}
      break FGColorLoop
      }
      }
      lissajous(w, cycles, res, size, frames, delay)
      }

      func lissajous(out io.Writer, cycles float64, res float64, size int, nframes int, delay int) {
      freq := rand.Float64() * 3.0
      anim := gif.GIF{LoopCount: nframes}
      phase := 0.0
      palette := color.Color{bgcolor, fgcolor}
      for i := 0; i<nframes; i++ {
      rect := image.Rect(0, 0, 2*size+1, 2*size+1)
      img := image.NewPaletted(rect, palette)
      for t:=0.0; t<cycles*2*math.Pi; t+=res {
      x := math.Sin(t)
      y := math.Sin(t*freq+phase)
      img.SetColorIndex(size+int(x*float64(size)+0.5), size+int(y*float64(size)+0.5), 1)
      }
      phase += 0.1
      anim.Delay = append(anim.Delay, delay)
      anim.Image = append(anim.Image, img)
      }
      gif.EncodeAll(out, &anim)
      }






      formatting go type-safety






      share|improve this question













      share|improve this question











      share|improve this question




      share|improve this question










      asked yesterday









      iwrestledabearonce

      2,022513




      2,022513






















          1 Answer
          1






          active

          oldest

          votes


















          1














          Code must be correct. To be sure that code is correct, code must be readable.





          I took some of your baffling code:



          var bgcolor = color.RGBA{0, 0, 0, 255}
          var fgcolor = color.RGBA{255, 255, 255, 255}

          if value, exists := r.Form["bgcolor"]; exists {
          BGColorLoop:
          for {
          parts := strings.Split(value[0], ",")
          if len(parts) != 3 {
          break BGColorLoop
          }
          for _, val := range parts {
          if v, err := strconv.ParseInt(val, 10, 0); err != nil || int(v) > 255 || int(v) < 0 {
          break BGColorLoop
          }
          }
          r, _ := strconv.ParseInt(parts[0], 10, 8)
          g, _ := strconv.ParseInt(parts[1], 10, 8)
          b, _ := strconv.ParseInt(parts[2], 10, 8)
          bgcolor = color.RGBA{uint8(r), uint8(g), uint8(b), 255}
          break BGColorLoop
          }
          }
          if value, exists := r.Form["fgcolor"]; exists {
          FGColorLoop:
          for {
          parts := strings.Split(value[0], ",")
          if len(parts) != 3 {
          break FGColorLoop
          }
          for _, val := range parts {
          if v, err := strconv.ParseInt(val, 10, 0); err != nil || int(v) > 255 || int(v) < 0 {
          break FGColorLoop
          }
          }
          r, _ := strconv.ParseInt(parts[0], 10, 8)
          g, _ := strconv.ParseInt(parts[1], 10, 8)
          b, _ := strconv.ParseInt(parts[2], 10, 8)
          fgcolor = color.RGBA{uint8(r), uint8(g), uint8(b), 255}
          break FGColorLoop
          }
          }


          I rewrote it (a first draft) in Go:



          bgcolor, err := formColor(r, "bgcolor")
          if err != nil {
          bgcolor = color.RGBA{0, 0, 0, 255}
          }
          fgcolor, err := formColor(r, "fgcolor")
          if err != nil {
          fgcolor = color.RGBA{255, 255, 255, 255}
          }


          Where



          var errFormColor = errors.New("invalid form color")

          func formColor(r *http.Request, colorKey string) (color.RGBA, error) {
          var rgb [3]uint8

          value := r.Form[colorKey]
          if len(value) <= 0 {
          return color.RGBA{}, errFormColor
          }
          parts := strings.SplitN(value[0], ",", len(rgb)+1)
          if len(parts) != len(rgb) {
          return color.RGBA{}, errFormColor
          }
          for i, part := range parts {
          p, err := strconv.ParseUint(part, 10, 8)
          if err != nil {
          return color.RGBA{}, errFormColor
          }
          rgb[i] = uint8(p)
          }

          return color.RGBA{rgb[0], rgb[1], rgb[2], 255}, nil
          }





          share|improve this answer























          • After fixing a few minor errors your code compiled, which surprised me because originally I had tried to delegate the same block of code to a function but it would not allow me to return the color. The compiler kept saying "color.RGBA is not a type." Eventually I gave up. I will try to duplicate that error later to see if I can figure out where I went wrong. Thanks for your input!
            – iwrestledabearonce
            16 hours ago











          Your Answer





          StackExchange.ifUsing("editor", function () {
          return StackExchange.using("mathjaxEditing", function () {
          StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
          StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
          });
          });
          }, "mathjax-editing");

          StackExchange.ifUsing("editor", function () {
          StackExchange.using("externalEditor", function () {
          StackExchange.using("snippets", function () {
          StackExchange.snippets.init();
          });
          });
          }, "code-snippets");

          StackExchange.ready(function() {
          var channelOptions = {
          tags: "".split(" "),
          id: "196"
          };
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function() {
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled) {
          StackExchange.using("snippets", function() {
          createEditor();
          });
          }
          else {
          createEditor();
          }
          });

          function createEditor() {
          StackExchange.prepareEditor({
          heartbeatType: 'answer',
          autoActivateHeartbeat: false,
          convertImagesToLinks: false,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: null,
          bindNavPrevention: true,
          postfix: "",
          imageUploader: {
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          },
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          });


          }
          });














          draft saved

          draft discarded


















          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f210962%2fgenerating-image-serving-via-http-with-go%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown

























          1 Answer
          1






          active

          oldest

          votes








          1 Answer
          1






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes









          1














          Code must be correct. To be sure that code is correct, code must be readable.





          I took some of your baffling code:



          var bgcolor = color.RGBA{0, 0, 0, 255}
          var fgcolor = color.RGBA{255, 255, 255, 255}

          if value, exists := r.Form["bgcolor"]; exists {
          BGColorLoop:
          for {
          parts := strings.Split(value[0], ",")
          if len(parts) != 3 {
          break BGColorLoop
          }
          for _, val := range parts {
          if v, err := strconv.ParseInt(val, 10, 0); err != nil || int(v) > 255 || int(v) < 0 {
          break BGColorLoop
          }
          }
          r, _ := strconv.ParseInt(parts[0], 10, 8)
          g, _ := strconv.ParseInt(parts[1], 10, 8)
          b, _ := strconv.ParseInt(parts[2], 10, 8)
          bgcolor = color.RGBA{uint8(r), uint8(g), uint8(b), 255}
          break BGColorLoop
          }
          }
          if value, exists := r.Form["fgcolor"]; exists {
          FGColorLoop:
          for {
          parts := strings.Split(value[0], ",")
          if len(parts) != 3 {
          break FGColorLoop
          }
          for _, val := range parts {
          if v, err := strconv.ParseInt(val, 10, 0); err != nil || int(v) > 255 || int(v) < 0 {
          break FGColorLoop
          }
          }
          r, _ := strconv.ParseInt(parts[0], 10, 8)
          g, _ := strconv.ParseInt(parts[1], 10, 8)
          b, _ := strconv.ParseInt(parts[2], 10, 8)
          fgcolor = color.RGBA{uint8(r), uint8(g), uint8(b), 255}
          break FGColorLoop
          }
          }


          I rewrote it (a first draft) in Go:



          bgcolor, err := formColor(r, "bgcolor")
          if err != nil {
          bgcolor = color.RGBA{0, 0, 0, 255}
          }
          fgcolor, err := formColor(r, "fgcolor")
          if err != nil {
          fgcolor = color.RGBA{255, 255, 255, 255}
          }


          Where



          var errFormColor = errors.New("invalid form color")

          func formColor(r *http.Request, colorKey string) (color.RGBA, error) {
          var rgb [3]uint8

          value := r.Form[colorKey]
          if len(value) <= 0 {
          return color.RGBA{}, errFormColor
          }
          parts := strings.SplitN(value[0], ",", len(rgb)+1)
          if len(parts) != len(rgb) {
          return color.RGBA{}, errFormColor
          }
          for i, part := range parts {
          p, err := strconv.ParseUint(part, 10, 8)
          if err != nil {
          return color.RGBA{}, errFormColor
          }
          rgb[i] = uint8(p)
          }

          return color.RGBA{rgb[0], rgb[1], rgb[2], 255}, nil
          }





          share|improve this answer























          • After fixing a few minor errors your code compiled, which surprised me because originally I had tried to delegate the same block of code to a function but it would not allow me to return the color. The compiler kept saying "color.RGBA is not a type." Eventually I gave up. I will try to duplicate that error later to see if I can figure out where I went wrong. Thanks for your input!
            – iwrestledabearonce
            16 hours ago
















          1














          Code must be correct. To be sure that code is correct, code must be readable.





          I took some of your baffling code:



          var bgcolor = color.RGBA{0, 0, 0, 255}
          var fgcolor = color.RGBA{255, 255, 255, 255}

          if value, exists := r.Form["bgcolor"]; exists {
          BGColorLoop:
          for {
          parts := strings.Split(value[0], ",")
          if len(parts) != 3 {
          break BGColorLoop
          }
          for _, val := range parts {
          if v, err := strconv.ParseInt(val, 10, 0); err != nil || int(v) > 255 || int(v) < 0 {
          break BGColorLoop
          }
          }
          r, _ := strconv.ParseInt(parts[0], 10, 8)
          g, _ := strconv.ParseInt(parts[1], 10, 8)
          b, _ := strconv.ParseInt(parts[2], 10, 8)
          bgcolor = color.RGBA{uint8(r), uint8(g), uint8(b), 255}
          break BGColorLoop
          }
          }
          if value, exists := r.Form["fgcolor"]; exists {
          FGColorLoop:
          for {
          parts := strings.Split(value[0], ",")
          if len(parts) != 3 {
          break FGColorLoop
          }
          for _, val := range parts {
          if v, err := strconv.ParseInt(val, 10, 0); err != nil || int(v) > 255 || int(v) < 0 {
          break FGColorLoop
          }
          }
          r, _ := strconv.ParseInt(parts[0], 10, 8)
          g, _ := strconv.ParseInt(parts[1], 10, 8)
          b, _ := strconv.ParseInt(parts[2], 10, 8)
          fgcolor = color.RGBA{uint8(r), uint8(g), uint8(b), 255}
          break FGColorLoop
          }
          }


          I rewrote it (a first draft) in Go:



          bgcolor, err := formColor(r, "bgcolor")
          if err != nil {
          bgcolor = color.RGBA{0, 0, 0, 255}
          }
          fgcolor, err := formColor(r, "fgcolor")
          if err != nil {
          fgcolor = color.RGBA{255, 255, 255, 255}
          }


          Where



          var errFormColor = errors.New("invalid form color")

          func formColor(r *http.Request, colorKey string) (color.RGBA, error) {
          var rgb [3]uint8

          value := r.Form[colorKey]
          if len(value) <= 0 {
          return color.RGBA{}, errFormColor
          }
          parts := strings.SplitN(value[0], ",", len(rgb)+1)
          if len(parts) != len(rgb) {
          return color.RGBA{}, errFormColor
          }
          for i, part := range parts {
          p, err := strconv.ParseUint(part, 10, 8)
          if err != nil {
          return color.RGBA{}, errFormColor
          }
          rgb[i] = uint8(p)
          }

          return color.RGBA{rgb[0], rgb[1], rgb[2], 255}, nil
          }





          share|improve this answer























          • After fixing a few minor errors your code compiled, which surprised me because originally I had tried to delegate the same block of code to a function but it would not allow me to return the color. The compiler kept saying "color.RGBA is not a type." Eventually I gave up. I will try to duplicate that error later to see if I can figure out where I went wrong. Thanks for your input!
            – iwrestledabearonce
            16 hours ago














          1












          1








          1






          Code must be correct. To be sure that code is correct, code must be readable.





          I took some of your baffling code:



          var bgcolor = color.RGBA{0, 0, 0, 255}
          var fgcolor = color.RGBA{255, 255, 255, 255}

          if value, exists := r.Form["bgcolor"]; exists {
          BGColorLoop:
          for {
          parts := strings.Split(value[0], ",")
          if len(parts) != 3 {
          break BGColorLoop
          }
          for _, val := range parts {
          if v, err := strconv.ParseInt(val, 10, 0); err != nil || int(v) > 255 || int(v) < 0 {
          break BGColorLoop
          }
          }
          r, _ := strconv.ParseInt(parts[0], 10, 8)
          g, _ := strconv.ParseInt(parts[1], 10, 8)
          b, _ := strconv.ParseInt(parts[2], 10, 8)
          bgcolor = color.RGBA{uint8(r), uint8(g), uint8(b), 255}
          break BGColorLoop
          }
          }
          if value, exists := r.Form["fgcolor"]; exists {
          FGColorLoop:
          for {
          parts := strings.Split(value[0], ",")
          if len(parts) != 3 {
          break FGColorLoop
          }
          for _, val := range parts {
          if v, err := strconv.ParseInt(val, 10, 0); err != nil || int(v) > 255 || int(v) < 0 {
          break FGColorLoop
          }
          }
          r, _ := strconv.ParseInt(parts[0], 10, 8)
          g, _ := strconv.ParseInt(parts[1], 10, 8)
          b, _ := strconv.ParseInt(parts[2], 10, 8)
          fgcolor = color.RGBA{uint8(r), uint8(g), uint8(b), 255}
          break FGColorLoop
          }
          }


          I rewrote it (a first draft) in Go:



          bgcolor, err := formColor(r, "bgcolor")
          if err != nil {
          bgcolor = color.RGBA{0, 0, 0, 255}
          }
          fgcolor, err := formColor(r, "fgcolor")
          if err != nil {
          fgcolor = color.RGBA{255, 255, 255, 255}
          }


          Where



          var errFormColor = errors.New("invalid form color")

          func formColor(r *http.Request, colorKey string) (color.RGBA, error) {
          var rgb [3]uint8

          value := r.Form[colorKey]
          if len(value) <= 0 {
          return color.RGBA{}, errFormColor
          }
          parts := strings.SplitN(value[0], ",", len(rgb)+1)
          if len(parts) != len(rgb) {
          return color.RGBA{}, errFormColor
          }
          for i, part := range parts {
          p, err := strconv.ParseUint(part, 10, 8)
          if err != nil {
          return color.RGBA{}, errFormColor
          }
          rgb[i] = uint8(p)
          }

          return color.RGBA{rgb[0], rgb[1], rgb[2], 255}, nil
          }





          share|improve this answer














          Code must be correct. To be sure that code is correct, code must be readable.





          I took some of your baffling code:



          var bgcolor = color.RGBA{0, 0, 0, 255}
          var fgcolor = color.RGBA{255, 255, 255, 255}

          if value, exists := r.Form["bgcolor"]; exists {
          BGColorLoop:
          for {
          parts := strings.Split(value[0], ",")
          if len(parts) != 3 {
          break BGColorLoop
          }
          for _, val := range parts {
          if v, err := strconv.ParseInt(val, 10, 0); err != nil || int(v) > 255 || int(v) < 0 {
          break BGColorLoop
          }
          }
          r, _ := strconv.ParseInt(parts[0], 10, 8)
          g, _ := strconv.ParseInt(parts[1], 10, 8)
          b, _ := strconv.ParseInt(parts[2], 10, 8)
          bgcolor = color.RGBA{uint8(r), uint8(g), uint8(b), 255}
          break BGColorLoop
          }
          }
          if value, exists := r.Form["fgcolor"]; exists {
          FGColorLoop:
          for {
          parts := strings.Split(value[0], ",")
          if len(parts) != 3 {
          break FGColorLoop
          }
          for _, val := range parts {
          if v, err := strconv.ParseInt(val, 10, 0); err != nil || int(v) > 255 || int(v) < 0 {
          break FGColorLoop
          }
          }
          r, _ := strconv.ParseInt(parts[0], 10, 8)
          g, _ := strconv.ParseInt(parts[1], 10, 8)
          b, _ := strconv.ParseInt(parts[2], 10, 8)
          fgcolor = color.RGBA{uint8(r), uint8(g), uint8(b), 255}
          break FGColorLoop
          }
          }


          I rewrote it (a first draft) in Go:



          bgcolor, err := formColor(r, "bgcolor")
          if err != nil {
          bgcolor = color.RGBA{0, 0, 0, 255}
          }
          fgcolor, err := formColor(r, "fgcolor")
          if err != nil {
          fgcolor = color.RGBA{255, 255, 255, 255}
          }


          Where



          var errFormColor = errors.New("invalid form color")

          func formColor(r *http.Request, colorKey string) (color.RGBA, error) {
          var rgb [3]uint8

          value := r.Form[colorKey]
          if len(value) <= 0 {
          return color.RGBA{}, errFormColor
          }
          parts := strings.SplitN(value[0], ",", len(rgb)+1)
          if len(parts) != len(rgb) {
          return color.RGBA{}, errFormColor
          }
          for i, part := range parts {
          p, err := strconv.ParseUint(part, 10, 8)
          if err != nil {
          return color.RGBA{}, errFormColor
          }
          rgb[i] = uint8(p)
          }

          return color.RGBA{rgb[0], rgb[1], rgb[2], 255}, nil
          }






          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited 16 hours ago

























          answered 18 hours ago









          peterSO

          1,19968




          1,19968












          • After fixing a few minor errors your code compiled, which surprised me because originally I had tried to delegate the same block of code to a function but it would not allow me to return the color. The compiler kept saying "color.RGBA is not a type." Eventually I gave up. I will try to duplicate that error later to see if I can figure out where I went wrong. Thanks for your input!
            – iwrestledabearonce
            16 hours ago


















          • After fixing a few minor errors your code compiled, which surprised me because originally I had tried to delegate the same block of code to a function but it would not allow me to return the color. The compiler kept saying "color.RGBA is not a type." Eventually I gave up. I will try to duplicate that error later to see if I can figure out where I went wrong. Thanks for your input!
            – iwrestledabearonce
            16 hours ago
















          After fixing a few minor errors your code compiled, which surprised me because originally I had tried to delegate the same block of code to a function but it would not allow me to return the color. The compiler kept saying "color.RGBA is not a type." Eventually I gave up. I will try to duplicate that error later to see if I can figure out where I went wrong. Thanks for your input!
          – iwrestledabearonce
          16 hours ago




          After fixing a few minor errors your code compiled, which surprised me because originally I had tried to delegate the same block of code to a function but it would not allow me to return the color. The compiler kept saying "color.RGBA is not a type." Eventually I gave up. I will try to duplicate that error later to see if I can figure out where I went wrong. Thanks for your input!
          – iwrestledabearonce
          16 hours ago


















          draft saved

          draft discarded




















































          Thanks for contributing an answer to Code Review Stack Exchange!


          • Please be sure to answer the question. Provide details and share your research!

          But avoid



          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.


          Use MathJax to format equations. MathJax reference.


          To learn more, see our tips on writing great answers.





          Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


          Please pay close attention to the following guidance:


          • Please be sure to answer the question. Provide details and share your research!

          But avoid



          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.


          To learn more, see our tips on writing great answers.




          draft saved


          draft discarded














          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f210962%2fgenerating-image-serving-via-http-with-go%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown





















































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown

































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown







          Popular posts from this blog

          How to reconfigure Docker Trusted Registry 2.x.x to use CEPH FS mount instead of NFS and other traditional...

          is 'sed' thread safe

          How to make a Squid Proxy server?