parent
f9d1f664f0
commit
0fdece68c0
@ -0,0 +1,113 @@ |
||||
package api |
||||
|
||||
import ( |
||||
"bytes" |
||||
"errors" |
||||
"fmt" |
||||
"image" |
||||
"image/jpeg" |
||||
"image/png" |
||||
"io" |
||||
"net/http" |
||||
"path/filepath" |
||||
"strings" |
||||
|
||||
"github.com/mediocregopher/blog.mediocregopher.com/srv/api/apiutil" |
||||
"github.com/mediocregopher/blog.mediocregopher.com/srv/post" |
||||
"golang.org/x/image/draw" |
||||
) |
||||
|
||||
func resizeImage(out io.Writer, in io.Reader, maxWidth float64) error { |
||||
|
||||
img, format, err := image.Decode(in) |
||||
if err != nil { |
||||
return fmt.Errorf("decoding image: %w", err) |
||||
} |
||||
|
||||
imgRect := img.Bounds() |
||||
imgW, imgH := float64(imgRect.Dx()), float64(imgRect.Dy()) |
||||
|
||||
if imgW > maxWidth { |
||||
|
||||
newH := imgH * maxWidth / imgW |
||||
newImg := image.NewRGBA(image.Rect(0, 0, int(maxWidth), int(newH))) |
||||
|
||||
// Resize
|
||||
draw.BiLinear.Scale( |
||||
newImg, newImg.Bounds(), img, img.Bounds(), draw.Over, nil, |
||||
) |
||||
|
||||
img = newImg |
||||
} |
||||
|
||||
switch format { |
||||
case "jpeg": |
||||
return jpeg.Encode(out, img, nil) |
||||
case "png": |
||||
return png.Encode(out, img) |
||||
default: |
||||
return fmt.Errorf("unknown image format %q", format) |
||||
} |
||||
} |
||||
|
||||
func (a *api) servePostAssetHandler() http.Handler { |
||||
|
||||
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { |
||||
|
||||
id := filepath.Base(r.URL.Path) |
||||
|
||||
maxWidth, err := apiutil.StrToInt(r.FormValue("w"), 0) |
||||
if err != nil { |
||||
apiutil.BadRequest(rw, r, fmt.Errorf("invalid w parameter: %w", err)) |
||||
return |
||||
} |
||||
|
||||
buf := new(bytes.Buffer) |
||||
|
||||
err = a.params.PostAssetStore.Get(id, buf) |
||||
|
||||
if errors.Is(err, post.ErrAssetNotFound) { |
||||
http.Error(rw, "Asset not found", 404) |
||||
return |
||||
} else if err != nil { |
||||
apiutil.InternalServerError( |
||||
rw, r, fmt.Errorf("fetching asset with id %q: %w", id, err), |
||||
) |
||||
return |
||||
} |
||||
|
||||
if maxWidth == 0 { |
||||
|
||||
if _, err := io.Copy(rw, buf); err != nil { |
||||
apiutil.InternalServerError( |
||||
rw, r, |
||||
fmt.Errorf( |
||||
"copying asset with id %q to response writer: %w", |
||||
id, err, |
||||
), |
||||
) |
||||
} |
||||
|
||||
return |
||||
} |
||||
|
||||
switch ext := strings.ToLower(strings.TrimPrefix(filepath.Ext(id), ".")); ext { |
||||
case "jpg", "jpeg", "png": |
||||
|
||||
if err := resizeImage(rw, buf, float64(maxWidth)); err != nil { |
||||
apiutil.InternalServerError( |
||||
rw, r, |
||||
fmt.Errorf( |
||||
"resizing image with id %q to size %d: %w", |
||||
id, maxWidth, err, |
||||
), |
||||
) |
||||
} |
||||
|
||||
default: |
||||
apiutil.BadRequest(rw, r, fmt.Errorf("cannot resize file with extension %q", ext)) |
||||
return |
||||
} |
||||
|
||||
}) |
||||
} |
Loading…
Reference in new issue