diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..62c085a --- /dev/null +++ b/Dockerfile @@ -0,0 +1,20 @@ +FROM golang:latest + +MAINTAINER Andreas Neue + +RUN apt -y update && \ + apt -y upgrade && \ + apt -y install libglib2.0-dev libexpat1-dev libjpeg-dev libpng-dev libgif-dev + +WORKDIR /go/src/image-resizer +COPY . . + +RUN wget https://github.com/libvips/libvips/releases/download/v8.7.3/vips-8.7.3.tar.gz && \ + tar xvzf vips-8.7.3.tar.gz && \ + cd vips-8.7.3 && \ + ./configure && \ + make && \ + make install + +RUN go get -v -u github.com/davidbyttow/govips/pkg/vips +RUN go install -v ./... diff --git a/main.go b/main.go new file mode 100644 index 0000000..dd941d0 --- /dev/null +++ b/main.go @@ -0,0 +1,89 @@ +// vi:ts=4:sts=4:sw=4:noet:tw=72 + +package main + +import ( + "fmt" + "log" + "net/http" + "strconv" + "strings" + + "github.com/davidbyttow/govips/pkg/vips" +) + +func main() { + // Start vips with the default configuration + vips.Startup(nil) + defer vips.Shutdown() + + http.HandleFunc("/", resizeHandler) + log.Fatal(http.ListenAndServe("0.0.0.0:4444", nil)) +} + +func resizeHandler(w http.ResponseWriter, r *http.Request) { + // Get the query parameters from the request URL + path := r.URL.EscapedPath() + parm := strings.Split(path, "/") + if len(parm) < 3 { + w.Write([]byte(fmt.Sprintf("url, width and height are required"))) + w.WriteHeader(http.StatusBadRequest) + return + } + queryUrl := parm[2] + size := strings.Split(parm[1], "x") + if len(size) < 2 { + w.Write([]byte(fmt.Sprintf("url, width and height are required"))) + w.WriteHeader(http.StatusBadRequest) + return + } + queryWidth := size[0] + queryHeight := size[1] + + // Validate that all three required fields are present + if queryUrl == "" || queryWidth == "" || queryHeight == "" { + w.Write([]byte(fmt.Sprintf("url, width and height are required"))) + w.WriteHeader(http.StatusBadRequest) + return + } + + // Convert width and height to integers + width, errW := strconv.Atoi(queryWidth) + height, errH := strconv.Atoi(queryHeight) + if errW != nil || errH != nil { + w.Write([]byte(fmt.Sprintf("width and height must be integers"))) + w.WriteHeader(http.StatusBadRequest) + return + } + + // Start fetching the image from the given url + resp, err := http.Get(queryUrl) + if err != nil { + w.Write([]byte(fmt.Sprintf("failed to get %s: %v", queryUrl, err))) + w.WriteHeader(http.StatusBadRequest) + return + } + + // Ensure that a valid response was given + if resp.StatusCode/100 != 2 { + w.Write([]byte(fmt.Sprintf("failed to get %s: status %d", queryUrl, resp.StatusCode))) + w.WriteHeader(http.StatusBadRequest) + return + } + defer resp.Body.Close() + + // govips returns the output of the image as a []byte object. We don't need + // it since we are directly piping it to the ResponseWriter + _, _, err = vips.NewTransform(). + Load(resp.Body). + ResizeStrategy(vips.ResizeStrategyStretch). + Resize(width, height). + Output(w). + Apply() + + if err != nil { + w.Write([]byte(fmt.Sprintf("failed to resize %s: %v", queryUrl, err))) + w.WriteHeader(http.StatusInternalServerError) + return + } +}