1
0
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:
DarthSim 2020-04-08 21:15:07 +06:00
parent 21b990d895
commit 6c348adb0b
5 changed files with 53 additions and 44 deletions

View File

@ -1,6 +1,8 @@
# Changelog
## [Unreleased]
### Added
- Fallback images.
## [2.12.0] - 2020-04-07
### Addded

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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
}