0
Fork 0
mirror of https://github.com/willnorris/imageproxy.git synced 2024-12-16 21:56:43 -05:00
imageproxy/data.go

164 lines
3.6 KiB
Go
Raw Normal View History

// Copyright 2013 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package imageproxy
import (
2013-12-26 15:50:22 -05:00
"bytes"
"fmt"
2013-12-26 17:38:15 -05:00
"net/http"
"net/url"
"strconv"
"strings"
)
2013-12-26 21:31:20 -05:00
// URLError reports a malformed URL error.
type URLError struct {
Message string
URL *url.URL
}
func (e URLError) Error() string {
return fmt.Sprintf("malformed URL %q: %s", e.URL, e.Message)
}
2013-12-05 02:12:44 -05:00
// Options specifies transformations that can be performed on a
// requested image.
2013-12-05 02:12:44 -05:00
type Options struct {
Width float64 // requested width, in pixels
Height float64 // 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
2013-12-06 21:03:16 -05:00
// Rotate image the specified degrees counter-clockwise. Valid values are 90, 180, 270.
Rotate int
FlipVertical bool
FlipHorizontal bool
}
var emptyOptions = Options{}
2013-12-26 18:04:14 -05:00
2013-12-05 02:12:44 -05:00
func (o Options) String() string {
2013-12-26 15:50:22 -05:00
buf := new(bytes.Buffer)
fmt.Fprintf(buf, "%vx%v", o.Width, o.Height)
if o.Fit {
buf.WriteString(",fit")
}
if o.Rotate != 0 {
fmt.Fprintf(buf, ",r%d", o.Rotate)
}
if o.FlipVertical {
buf.WriteString(",fv")
}
if o.FlipHorizontal {
buf.WriteString(",fh")
}
return buf.String()
}
func ParseOptions(str string) Options {
o := Options{}
parts := strings.Split(str, ",")
for _, part := range parts {
if part == "fit" {
o.Fit = true
2013-12-06 21:03:16 -05:00
continue
}
if part == "fv" {
o.FlipVertical = true
continue
}
if part == "fh" {
o.FlipHorizontal = true
continue
}
if len(part) > 2 && part[:1] == "r" {
2013-12-07 20:06:36 -05:00
o.Rotate, _ = strconv.Atoi(part[1:])
2013-12-06 21:03:16 -05:00
continue
}
if strings.ContainsRune(part, 'x') {
var h, w string
size := strings.SplitN(part, "x", 2)
w = size[0]
if len(size) > 1 {
h = size[1]
} else {
h = w
}
if w != "" {
o.Width, _ = strconv.ParseFloat(w, 64)
}
if h != "" {
o.Height, _ = strconv.ParseFloat(h, 64)
}
continue
}
if size, err := strconv.ParseFloat(part, 64); err == nil {
o.Width = size
o.Height = size
continue
}
}
return o
}
type Request struct {
2013-12-05 02:12:44 -05:00
URL *url.URL // URL of the image to proxy
Options Options // Image transformation to perform
}
2013-12-26 17:38:15 -05:00
// NewRequest parses an http.Request into an image request.
func NewRequest(r *http.Request) (*Request, error) {
var err error
req := new(Request)
path := r.URL.Path[1:] // strip leading slash
req.URL, err = url.Parse(path)
if err != nil || !req.URL.IsAbs() {
// first segment is likely options
parts := strings.SplitN(path, "/", 2)
if len(parts) != 2 {
return nil, URLError{"too few path segments", r.URL}
}
req.URL, err = url.Parse(parts[1])
if err != nil {
return nil, URLError{fmt.Sprintf("unable to parse remote URL: %v", err), r.URL}
}
req.Options = ParseOptions(parts[0])
}
if !req.URL.IsAbs() {
return nil, URLError{"must provide absolute remote URL", r.URL}
}
if req.URL.Scheme != "http" && req.URL.Scheme != "https" {
return nil, URLError{"remote URL must have http or https scheme", r.URL}
2013-12-26 17:38:15 -05:00
}
// query string is always part of the remote URL
req.URL.RawQuery = r.URL.RawQuery
return req, nil
}