mirror of
https://github.com/imgproxy/imgproxy.git
synced 2024-11-24 08:12:38 +02:00
Minor changes in fallback images feature; Add docs for fallback images
This commit is contained in:
parent
21b990d895
commit
6c348adb0b
@ -1,6 +1,8 @@
|
||||
# Changelog
|
||||
|
||||
## [Unreleased]
|
||||
### Added
|
||||
- Fallback images.
|
||||
|
||||
## [2.12.0] - 2020-04-07
|
||||
### Addded
|
||||
|
@ -155,6 +155,14 @@ imgproxy Pro can extract specific frames of videos to create thumbnails. The fea
|
||||
|
||||
Read more about watermarks in the [Watermark](watermark.md) guide.
|
||||
|
||||
## Fallback image
|
||||
|
||||
You can set up a fallback image that will be used in case imgproxy can't fetch the requested one. Use one of the following variables:
|
||||
|
||||
* `IMGPROXY_FALLBACK_IMAGE_DATA`: Base64-encoded image data. You can easily calculate it with `base64 tmp/fallback.png | tr -d '\n'`;
|
||||
* `IMGPROXY_FALLBACK_IMAGE_PATH`: path to the locally stored image;
|
||||
* `IMGPROXY_FALLBACK_IMAGE_URL`: fallback image URL.
|
||||
|
||||
## Presets
|
||||
|
||||
Read about imgproxy presets in the [Presets](presets.md) guide.
|
||||
|
13
download.go
13
download.go
@ -30,19 +30,6 @@ const msgSourceImageIsUnreachable = "Source image is unreachable"
|
||||
|
||||
var downloadBufPool *bufPool
|
||||
|
||||
type imageData struct {
|
||||
Data []byte
|
||||
Type imageType
|
||||
|
||||
cancel context.CancelFunc
|
||||
}
|
||||
|
||||
func (d *imageData) Close() {
|
||||
if d.cancel != nil {
|
||||
d.cancel()
|
||||
}
|
||||
}
|
||||
|
||||
type limitReader struct {
|
||||
r io.Reader
|
||||
left int
|
||||
|
@ -2,22 +2,36 @@ package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
type imageData struct {
|
||||
Data []byte
|
||||
Type imageType
|
||||
|
||||
cancel context.CancelFunc
|
||||
}
|
||||
|
||||
func (d *imageData) Close() {
|
||||
if d.cancel != nil {
|
||||
d.cancel()
|
||||
}
|
||||
}
|
||||
|
||||
func getWatermarkData() (*imageData, error) {
|
||||
if len(conf.WatermarkData) > 0 {
|
||||
return base64ImageData(conf.WatermarkData)
|
||||
return base64ImageData(conf.WatermarkData, "watermark")
|
||||
}
|
||||
|
||||
if len(conf.WatermarkPath) > 0 {
|
||||
return fileImageData(conf.WatermarkPath)
|
||||
return fileImageData(conf.WatermarkPath, "watermark")
|
||||
}
|
||||
|
||||
if len(conf.WatermarkURL) > 0 {
|
||||
return remoteImageData(conf.WatermarkURL)
|
||||
return remoteImageData(conf.WatermarkURL, "watermark")
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
@ -25,65 +39,65 @@ func getWatermarkData() (*imageData, error) {
|
||||
|
||||
func getFallbackImageData() (*imageData, error) {
|
||||
if len(conf.FallbackImageData) > 0 {
|
||||
return base64ImageData(conf.FallbackImageData)
|
||||
return base64ImageData(conf.FallbackImageData, "fallback image")
|
||||
}
|
||||
|
||||
if len(conf.FallbackImagePath) > 0 {
|
||||
return fileImageData(conf.FallbackImagePath)
|
||||
return fileImageData(conf.FallbackImagePath, "fallback image")
|
||||
}
|
||||
|
||||
if len(conf.FallbackImageURL) > 0 {
|
||||
return remoteImageData(conf.FallbackImageURL)
|
||||
return remoteImageData(conf.FallbackImageURL, "fallback image")
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func base64ImageData(encoded string) (*imageData, error) {
|
||||
func base64ImageData(encoded, desc string) (*imageData, error) {
|
||||
data, err := base64.StdEncoding.DecodeString(encoded)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Can't decode image data: %s", err)
|
||||
return nil, fmt.Errorf("Can't decode %s data: %s", desc, err)
|
||||
}
|
||||
|
||||
imgtype, err := checkTypeAndDimensions(bytes.NewReader(data))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Can't decode image: %s", err)
|
||||
return nil, fmt.Errorf("Can't decode %s: %s", desc, err)
|
||||
}
|
||||
|
||||
return &imageData{Data: data, Type: imgtype}, nil
|
||||
}
|
||||
|
||||
func fileImageData(path string) (*imageData, error) {
|
||||
func fileImageData(path, desc string) (*imageData, error) {
|
||||
f, err := os.Open(path)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Can't read watermark: %s", err)
|
||||
return nil, fmt.Errorf("Can't read %s: %s", desc, err)
|
||||
}
|
||||
|
||||
fi, err := f.Stat()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Can't read watermark: %s", err)
|
||||
return nil, fmt.Errorf("Can't read %s: %s", desc, err)
|
||||
}
|
||||
|
||||
imgdata, err := readAndCheckImage(f, int(fi.Size()))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Can't read watermark: %s", err)
|
||||
return nil, fmt.Errorf("Can't read %s: %s", desc, err)
|
||||
}
|
||||
|
||||
return imgdata, err
|
||||
}
|
||||
|
||||
func remoteImageData(imageURL string) (*imageData, error) {
|
||||
func remoteImageData(imageURL, desc string) (*imageData, error) {
|
||||
res, err := requestImage(imageURL)
|
||||
if res != nil {
|
||||
defer res.Body.Close()
|
||||
}
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Can't download image: %s", err)
|
||||
return nil, fmt.Errorf("Can't download %s: %s", desc, err)
|
||||
}
|
||||
|
||||
imgdata, err := readAndCheckImage(res.Body, int(res.ContentLength))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Can't download image: %s", err)
|
||||
return nil, fmt.Errorf("Can't download %s: %s", desc, err)
|
||||
}
|
||||
|
||||
return imgdata, err
|
||||
|
@ -16,14 +16,15 @@ var (
|
||||
processingSem chan struct{}
|
||||
|
||||
headerVaryValue string
|
||||
fallback *imageData
|
||||
fallbackImage *imageData
|
||||
)
|
||||
|
||||
func initProcessingHandler() error {
|
||||
var err error
|
||||
|
||||
processingSem = make(chan struct{}, conf.Concurrency)
|
||||
|
||||
if conf.GZipCompression > 0 {
|
||||
var err error
|
||||
responseGzipBufPool = newBufPool("gzip", conf.Concurrency, conf.GZipBufferSize)
|
||||
if responseGzipPool, err = newGzipPool(conf.Concurrency); err != nil {
|
||||
return err
|
||||
@ -46,7 +47,7 @@ func initProcessingHandler() error {
|
||||
|
||||
headerVaryValue = strings.Join(vary, ", ")
|
||||
|
||||
if err := loadFallback(); err != nil {
|
||||
if fallbackImage, err = getFallbackImageData(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -158,12 +159,17 @@ func handleProcessing(reqID string, rw http.ResponseWriter, r *http.Request) {
|
||||
if prometheusEnabled {
|
||||
incrementPrometheusErrorsTotal("download")
|
||||
}
|
||||
if fallback != nil {
|
||||
logError("Could not load image. Using fallback image: %s", err.Error())
|
||||
ctx = context.WithValue(ctx, imageDataCtxKey, fallback)
|
||||
} else {
|
||||
|
||||
if fallbackImage == nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if ierr, ok := err.(*imgproxyError); !ok || ierr.Unexpected {
|
||||
reportError(err, r)
|
||||
}
|
||||
|
||||
logWarning("Could not load image. Using fallback image: %s", err.Error())
|
||||
ctx = context.WithValue(ctx, imageDataCtxKey, fallbackImage)
|
||||
}
|
||||
|
||||
checkTimeout(ctx)
|
||||
@ -196,11 +202,3 @@ func handleProcessing(reqID string, rw http.ResponseWriter, r *http.Request) {
|
||||
|
||||
respondWithImage(ctx, reqID, r, rw, imageData)
|
||||
}
|
||||
|
||||
func loadFallback() (err error) {
|
||||
fallback, err = getFallbackImageData()
|
||||
if err != nil {
|
||||
logError("Could not load fallback data. Fallback images will not be available: %s", err.Error())
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user