diff --git a/data/data.go b/data/data.go index f0497a6..2fab83a 100644 --- a/data/data.go +++ b/data/data.go @@ -2,7 +2,6 @@ package data import ( - "errors" "fmt" "net/url" "strconv" @@ -15,18 +14,24 @@ import ( type Options struct { Width int // requested width, in pixels Height int // requested height, in pixels + + // If true, resize the image to fit in the specified dimensions. Image + // will not be cropped, and aspect ratio will be maintained. + Fit bool } func (o Options) String() string { return fmt.Sprintf("%dx%d", o.Width, o.Height) } -func ParseOptions(str string) (*Options, error) { - t := new(Options) - var err error +func ParseOptions(str string) *Options { + o := new(Options) var h, w string - size := strings.SplitN(str, "x", 2) + parts := strings.Split(str, ",") + + // parse size + size := strings.SplitN(parts[0], "x", 2) w = size[0] if len(size) > 1 { h = size[1] @@ -35,19 +40,19 @@ func ParseOptions(str string) (*Options, error) { } if w != "" { - t.Width, err = strconv.Atoi(w) - if err != nil { - return nil, errors.New("width must be an int") - } + o.Width, _ = strconv.Atoi(w) } if h != "" { - t.Height, err = strconv.Atoi(h) - if err != nil { - return nil, errors.New("height must be an int") + o.Height, _ = strconv.Atoi(h) + } + + for _, part := range parts[1:] { + if part == "fit" { + o.Fit = true } } - return t, nil + return o } type Request struct { diff --git a/proxy/proxy.go b/proxy/proxy.go index 1b3f34a..d410604 100644 --- a/proxy/proxy.go +++ b/proxy/proxy.go @@ -46,10 +46,7 @@ func NewRequest(r *http.Request) (*data.Request, error) { return nil, URLError{fmt.Sprintf("unable to parse remote URL: %v", err), r.URL} } - req.Options, err = data.ParseOptions(parts[0]) - if err != nil { - return nil, URLError{err.Error(), r.URL} - } + req.Options = data.ParseOptions(parts[0]) } if !req.URL.IsAbs() { diff --git a/proxy/proxy_test.go b/proxy/proxy_test.go index d879379..d23f872 100644 --- a/proxy/proxy_test.go +++ b/proxy/proxy_test.go @@ -30,11 +30,15 @@ func TestNewRequest(t *testing.T) { { "http://localhost//ftp://example.com/foo", "", nil, true, }, + + // invalid options. These won't return errors, but will not fully parse the options { - "http://localhost/s/http://example.com/", "", nil, true, + "http://localhost/s/http://example.com/", + "http://example.com/", emptyOptions, false, }, { - "http://localhost/1xs/http://example.com/", "", nil, true, + "http://localhost/1xs/http://example.com/", + "http://example.com/", &data.Options{Width: 1}, false, }, // valid URLs @@ -66,15 +70,23 @@ func TestNewRequest(t *testing.T) { }, { "http://localhost/1x/http://example.com/", - "http://example.com/", &data.Options{1, 0}, false, + "http://example.com/", &data.Options{1, 0, false}, false, }, { "http://localhost/x1/http://example.com/", - "http://example.com/", &data.Options{0, 1}, false, + "http://example.com/", &data.Options{0, 1, false}, false, }, { "http://localhost/1x2/http://example.com/", - "http://example.com/", &data.Options{1, 2}, false, + "http://example.com/", &data.Options{1, 2, false}, false, + }, + { + "http://localhost/,fit/http://example.com/", + "http://example.com/", &data.Options{0, 0, true}, false, + }, + { + "http://localhost/1x2,fit/http://example.com/", + "http://example.com/", &data.Options{1, 2, true}, false, }, } diff --git a/transform/transform.go b/transform/transform.go index 91694d2..4bfac30 100644 --- a/transform/transform.go +++ b/transform/transform.go @@ -18,6 +18,14 @@ var emptyOptions = new(data.Options) // Transform the provided image. func Transform(img data.Image, opt *data.Options) (*data.Image, error) { if opt == nil || reflect.DeepEqual(opt, emptyOptions) { + // bail if no transformation was requested + return &img, nil + } + + if opt.Width == 0 && opt.Height == 0 { + // TODO(willnorris): Currently, only resize related options are + // supported, so bail if no sizes are specified. Remove this + // check if we ever support non-resizing transformations. return &img, nil } @@ -28,8 +36,10 @@ func Transform(img data.Image, opt *data.Options) (*data.Image, error) { } // resize - if opt.Width != 0 || opt.Height != 0 { + if opt.Fit { m = imaging.Fit(m, opt.Width, opt.Height, imaging.Lanczos) + } else { + m = imaging.Resize(m, opt.Width, opt.Height, imaging.Lanczos) } // encode image