diff --git a/CHANGELOG.md b/CHANGELOG.md index f5754a6e..055897ee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ - AVIF support. - Azure Blob Storage support. - `IMGPROXY_STRIP_COLOR_PROFILE` config and [strip_color_profile](https://docs.imgproxy.net/#/generating_the_url_advanced?id=strip-color-profile) processing option. +- `IMGPROXY_FORMAT_QUALITY` config. - (pro) Remove Adobe Illustrator garbage from SVGs. ### Changed diff --git a/config.go b/config.go index 8a7e5357..06a8f3df 100644 --- a/config.go +++ b/config.go @@ -75,6 +75,34 @@ func imageTypesEnvConfig(it *[]imageType, name string) { } } +func formatQualityEnvConfig(m map[imageType]int, name string) { + if env := os.Getenv(name); len(env) > 0 { + parts := strings.Split(env, ",") + + for _, p := range parts { + i := strings.Index(p, "=") + if i < 0 { + logWarning("Invalid format quality string: %s", p) + continue + } + + imgtypeStr, qStr := strings.TrimSpace(p[:i]), strings.TrimSpace(p[i+1:]) + + imgtype, ok := imageTypes[imgtypeStr] + if !ok { + logWarning("Invalid format: %s", p) + } + + q, err := strconv.Atoi(qStr) + if err != nil || q <= 0 || q > 100 { + logWarning("Invalid quality: %s", p) + } + + m[imgtype] = q + } + } +} + func hexEnvConfig(b *[]securityKey, name string) error { var err error @@ -197,6 +225,7 @@ type config struct { PngQuantize bool PngQuantizationColors int Quality int + FormatQuality map[imageType]int GZipCompression int StripMetadata bool StripColorProfile bool @@ -291,6 +320,7 @@ var conf = config{ SignatureSize: 32, PngQuantizationColors: 256, Quality: 80, + FormatQuality: map[imageType]int{imageTypeAVIF: 50}, StripMetadata: true, StripColorProfile: true, UserAgent: fmt.Sprintf("imgproxy/%s", version), @@ -349,6 +379,7 @@ func configure() error { boolEnvConfig(&conf.PngQuantize, "IMGPROXY_PNG_QUANTIZE") intEnvConfig(&conf.PngQuantizationColors, "IMGPROXY_PNG_QUANTIZATION_COLORS") intEnvConfig(&conf.Quality, "IMGPROXY_QUALITY") + formatQualityEnvConfig(conf.FormatQuality, "IMGPROXY_FORMAT_QUALITY") intEnvConfig(&conf.GZipCompression, "IMGPROXY_GZIP_COMPRESSION") boolEnvConfig(&conf.StripMetadata, "IMGPROXY_STRIP_METADATA") boolEnvConfig(&conf.StripColorProfile, "IMGPROXY_STRIP_COLOR_PROFILE") diff --git a/docs/configuration.md b/docs/configuration.md index 07772f8c..d7f11e46 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -87,6 +87,7 @@ Also you may want imgproxy to respond with the same error message that it writes ## Compression * `IMGPROXY_QUALITY`: default quality of the resulting image, percentage. Default: `80`; +* `IMGPROXY_FORMAT_QUALITY`: default quality of the resulting image per format, comma divided. Example: `jpeg=70,avif=40,webp=60`. When value for the resulting format is not set, `IMGPROXY_QUALITY` value is used. Default: `avif=50`. * `IMGPROXY_GZIP_COMPRESSION`: GZip compression level. Default: `5`. ### Advanced JPEG compression diff --git a/docs/generating_the_url_advanced.md b/docs/generating_the_url_advanced.md index f1e6ab9d..82fb5cf6 100644 --- a/docs/generating_the_url_advanced.md +++ b/docs/generating_the_url_advanced.md @@ -215,9 +215,9 @@ quality:%quality q:%quality ``` -Redefines quality of the resulting image, percentage. +Redefines quality of the resulting image, percentage. When `0`, quality is assumed based on `IMGPROXY_QUALITY` and `IMGPROXY_FORMAT_QUALITY`. -Default: value from the environment variable. +Default: 0. #### Max Bytes diff --git a/process.go b/process.go index 176fcbec..4a3b172f 100644 --- a/process.go +++ b/process.go @@ -678,7 +678,7 @@ func getIcoData(imgdata *imageData) (*imageData, error) { func saveImageToFitBytes(po *processingOptions, img *vipsImage) ([]byte, context.CancelFunc, error) { var diff float64 - quality := po.Quality + quality := po.getQuality() img.CopyMemory() @@ -806,5 +806,5 @@ func processImage(ctx context.Context) ([]byte, context.CancelFunc, error) { return saveImageToFitBytes(po, img) } - return img.Save(po.Format, po.Quality) + return img.Save(po.Format, po.getQuality()) } diff --git a/processing_options.go b/processing_options.go index 9330af50..4e413410 100644 --- a/processing_options.go +++ b/processing_options.go @@ -221,7 +221,7 @@ func newProcessingOptions() *processingOptions { Extend: extendOptions{Enabled: false, Gravity: gravityOptions{Type: gravityCenter}}, Padding: paddingOptions{Enabled: false}, Trim: trimOptions{Enabled: false, Threshold: 10, Smart: true}, - Quality: conf.Quality, + Quality: 0, MaxBytes: 0, Format: imageTypeUnknown, Background: rgbColor{255, 255, 255}, @@ -240,6 +240,20 @@ func newProcessingOptions() *processingOptions { return &po } +func (po *processingOptions) getQuality() int { + q := po.Quality + + if q == 0 { + q = conf.FormatQuality[po.Format] + } + + if q == 0 { + q = conf.Quality + } + + return q +} + func (po *processingOptions) isPresetUsed(name string) bool { for _, usedName := range po.UsedPresets { if usedName == name { @@ -653,7 +667,7 @@ func applyQualityOption(po *processingOptions, args []string) error { return fmt.Errorf("Invalid quality arguments: %v", args) } - if q, err := strconv.Atoi(args[0]); err == nil && q > 0 && q <= 100 { + if q, err := strconv.Atoi(args[0]); err == nil && q >= 0 && q <= 100 { po.Quality = q } else { return fmt.Errorf("Invalid quality: %s", args[0])