mirror of
https://github.com/willnorris/imageproxy.git
synced 2025-01-06 22:40:34 -05:00
accept "fit" option
this also relaxes option parsing to never return an error. In cases where options are not able to be parsed, they are silently ignored.
This commit is contained in:
parent
805aa606ca
commit
2794d47390
4 changed files with 47 additions and 23 deletions
31
data/data.go
31
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 {
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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,
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue