it's a box

master
Jordan Orelli 8 years ago
parent 862e9c5e8d
commit c5bad7bcc6

@ -0,0 +1,48 @@
package main
import (
"image/color"
"testing"
)
var (
white = color.RGBA{0xff, 0xff, 0xff, 0xff}
red = color.RGBA{0xff, 0, 0, 0xff}
green = color.RGBA{0, 0xff, 0, 0xff}
blue = color.RGBA{0, 0, 0xff, 0xff}
)
func TestParseColor(t *testing.T) {
white := color.RGBA{0xff, 0xff, 0xff, 0xff}
eq := func(c1, c2 color.Color) bool {
r1, g1, b1, a1 := c1.RGBA()
r2, g2, b2, a2 := c2.RGBA()
return r1 == r2 && g1 == g2 && b1 == b2 && a1 == a2
}
type test struct {
in string
out color.RGBA
}
var tests = []test{
{"", white},
{"0000ff", blue},
{"0000ffff", blue},
{"00ff00", green},
{"00ff00ff", green},
{"ff0000", red},
{"ff0000ff", red},
{"FF0000", red},
}
for _, tt := range tests {
c := parseColor(tt.in)
if eq(c, tt.out) {
t.Logf("ok: '%s' == %v", tt.in, c)
} else {
t.Errorf("parse color failed: '%s' yielded %v, expected %v", tt.in, c, tt.out)
}
}
}

@ -17,10 +17,12 @@ func init() {
func main() {
flag.Parse()
s := server{
out: os.Stdout,
errors: os.Stderr,
}
if err := http.ListenAndServe(options.Host, &s); err != nil {
fmt.Fprintf(os.Stderr, "error: %v\n", err)
}

@ -2,8 +2,14 @@ package main
import (
"fmt"
"image"
"image/color"
"image/draw"
"image/png"
"io"
"net/http"
"strconv"
"strings"
)
type server struct {
@ -17,4 +23,96 @@ func (s *server) logReceived(r *http.Request) {
func (s *server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
s.logReceived(r)
encoder, err := getEncoding(r)
if err != nil {
s.writeError(w, err)
return
}
width := 400
width_s := r.URL.Query().Get("w")
if width_s != "" {
n, err := strconv.Atoi(width_s)
if err == nil {
width = n
}
}
height := 400
height_s := r.URL.Query().Get("h")
if height_s != "" {
n, err := strconv.Atoi(height_s)
if err == nil {
height = n
}
}
bg := parseColor(r.URL.Query().Get("bg"))
m := image.NewRGBA(image.Rect(0, 0, width, height))
draw.Draw(m, m.Bounds(), &image.Uniform{bg}, m.Bounds().Min, draw.Src)
encoder.WriteImage(w, m)
}
func parseColor(c_s string) color.RGBA {
f := func(s string) (n uint8) {
if len(s) != 2 {
return 0
}
i, err := strconv.ParseUint(s, 16, 0)
if err != nil {
return 0
}
return uint8(i)
}
white := color.RGBA{0xff, 0xff, 0xff, 0xff}
c_s = strings.ToLower(c_s)
switch len(c_s) {
case 2:
n := f(c_s[0:2])
return color.RGBA{n, n, n, 0xff}
case 4:
n, a := f(c_s[0:2]), f(c_s[2:4])
return color.RGBA{n, n, n, a}
case 6:
return color.RGBA{f(c_s[0:2]), f(c_s[2:4]), f(c_s[4:6]), 0xff}
case 8:
return color.RGBA{f(c_s[0:2]), f(c_s[2:4]), f(c_s[4:6]), f(c_s[6:8])}
default:
return white
}
}
type imageWriter interface {
WriteImage(w http.ResponseWriter, m image.Image)
}
type pngWriter struct {
CompressionLevel png.CompressionLevel
}
func (w pngWriter) WriteImage(rw http.ResponseWriter, m image.Image) {
enc := png.Encoder{CompressionLevel: w.CompressionLevel}
rw.Header().Add("Content-Type", "image/png")
enc.Encode(rw, m)
}
func getEncoding(r *http.Request) (imageWriter, error) {
parts := strings.Split(r.URL.Path, ".")
if len(parts) == 0 {
return nil, fmt.Errorf("no encoding specified")
}
switch e := parts[len(parts)-1]; e {
case "png":
return pngWriter{CompressionLevel: png.DefaultCompression}, nil
default:
return nil, fmt.Errorf("invalid encoding: %s", e)
}
}
func (s *server) writeError(w http.ResponseWriter, err error) {
fmt.Fprintf(s.errors, "E %s\n", err)
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(err.Error()))
}

Loading…
Cancel
Save