func newResizeHandler(ro resizeOpts) func(http.ResponseWriter, *http.Request) { return func(w http.ResponseWriter, r *http.Request) { log.Println("Starting resizeHandler") imageKey := r.URL.Path[len(ro.path):] // fetch the query param resizeQuery := r.URL.Query().Get("resize") key := fmt.Sprintf("%s/%s", ro.prefix, imageKey) if resizeQuery == "" { log.Println("Completed resizeHandler: Redirected, no resize parameter") urlStr := fmt.Sprintf("https://s3-%s.amazonaws.com/%s/%s", ro.region, ro.bucket, key) http.Redirect(w, r, urlStr, http.StatusTemporaryRedirect) return } resizeX, resizeY, err := waltz.ParseResize(resizeQuery) if err != nil { log.Println("Completed resizeHandler: ERROR: Resize parameters invalid:", err.Error()) http.Error(w, "", http.StatusBadRequest) return } params := &s3.GetObjectInput{ Bucket: aws.String(ro.bucket), Key: aws.String(key), } log.Println("Getting", *params.Key, "from bucket", *params.Bucket) ifNoneMatch := r.Header.Get("If-None-Match") if ifNoneMatch != "" { params.IfNoneMatch = aws.String(ifNoneMatch) } resp, err := ro.client.GetObject(params) if err != nil { if awsErr, ok := err.(awserr.Error); ok { if reqErr, ok := err.(awserr.RequestFailure); ok { // if this is a not modified error, then cut quick if reqErr.StatusCode() == http.StatusNotModified { log.Println("Completed resizeHandler: Object not modified") w.WriteHeader(http.StatusNotModified) return } if reqErr.StatusCode() == http.StatusNotFound { log.Println("Completed resizeHandler: Key not found") w.WriteHeader(http.StatusNotFound) return } // A service error occurred log.Println("Completed resizeHandler: ERROR: AWS Service error:", reqErr.Code(), reqErr.Message(), reqErr.StatusCode(), reqErr.RequestID()) http.Error(w, "", http.StatusInternalServerError) return } // Generic AWS error with Code, Message, and original error (if any) log.Println("Completed resizeHandler: ERROR: Generic AWS error:", awsErr.Code(), awsErr.Message(), awsErr.OrigErr()) http.Error(w, "", http.StatusInternalServerError) return } // This case should never be hit, the SDK should always return an // error which satisfies the awserr.Error interface. log.Println("Completed resizeHandler: ERROR: Impossible error:", err.Error()) http.Error(w, "", http.StatusInternalServerError) return } // write out the content type w.Header().Set("Cache-control", fmt.Sprintf("public, max-age=%d", int64(imageExpiry.Seconds()))) w.Header().Set("Content-Type", *resp.ContentType) w.Header().Set("Etag", *resp.ETag) if err := waltz.Do(resp.Body, w, nil, resizeX, resizeY); err != nil { log.Println("Completed resizeHandler: ERROR: Resize Error:", err.Error()) http.Error(w, "", http.StatusInternalServerError) return } } }
func main() { // use all CPU cores for maximum performance runtime.GOMAXPROCS(runtime.NumCPU()) // crop points var cropTLX, cropTLY, cropBRX, cropBRY int // resize points var resizeX, resizeY int // string components var crop, resize string flag.StringVar(&crop, "crop", "", "crop dimensions as 0x0,32x32 to indicate bounds") flag.StringVar(&resize, "resize", "", "resize dimensions after the crop as 16x16") flag.Parse() var ( cropRectangle *image.Rectangle err error ) if crop != "" { crop1 := strings.Split(crop, ",") if len(crop1) != 2 { log.Fatalf("crop invalid, should be in the form of 0x0,32x32") } crop2TL := strings.Split(crop1[0], "x") if len(crop2TL) != 2 { log.Fatalf("crop invalid, should be in the form of 0x0,32x32") } crop2BR := strings.Split(crop1[1], "x") if len(crop2BR) != 2 { log.Fatalf("crop invalid, should be in the form of 0x0,32x32") } if cropTLX, err = strconv.Atoi(crop2TL[0]); err != nil { log.Fatalln("crop invalid, should be in the form of 0x0,32x32") } if cropTLY, err = strconv.Atoi(crop2TL[1]); err != nil { log.Fatalln("crop invalid, should be in the form of 0x0,32x32") } if cropBRX, err = strconv.Atoi(crop2BR[0]); err != nil { log.Fatalln("crop invalid, should be in the form of 0x0,32x32") } if cropBRY, err = strconv.Atoi(crop2BR[1]); err != nil { log.Fatalln("crop invalid, should be in the form of 0x0,32x32") } cr := image.Rect(cropTLX, cropTLY, cropBRX, cropBRY) cropRectangle = &cr } resize1 := strings.Split(resize, "x") if len(resize1) < 1 { log.Fatalln("resize invalid, should be in the form 16x16") } if resizeX, err = strconv.Atoi(resize1[0]); err != nil { log.Fatalln("resize invalid, should be in the form 16x16") } if len(resize1) == 2 { if resizeY, err = strconv.Atoi(resize1[1]); err != nil { log.Fatalln("resize invalid, should be in the form 16x16") } } if err := waltz.Do(os.Stdin, os.Stdout, cropRectangle, resizeX, resizeY); err != nil { log.Fatalf("An error occured performing the resize: %s\n", err.Error()) } }