Răsfoiți Sursa

Add ENV setting for AVIF speed parameter (#605)

* Add ENV setting for AVIF speed parameter

* Add AVIF to image format docs

* Only use Speed on supported VIPS version

* Probably need the method signature in go to have speed
Per Osbäck 4 ani în urmă
părinte
comite
a7d451b8f2
6 a modificat fișierele cu 37 adăugiri și 5 ștergeri
  1. 9 0
      config.go
  2. 1 0
      docs/configuration.md
  3. 5 0
      docs/image_formats_support.md
  4. 16 2
      vips.c
  5. 3 2
      vips.go
  6. 3 1
      vips.h

+ 9 - 0
config.go

@@ -225,6 +225,7 @@ type config struct {
 	PngInterlaced         bool
 	PngQuantize           bool
 	PngQuantizationColors int
+	AvifSpeed             int
 	Quality               int
 	FormatQuality         map[imageType]int
 	GZipCompression       int
@@ -324,6 +325,7 @@ var conf = config{
 	SignatureSize:                  32,
 	PngQuantizationColors:          256,
 	Quality:                        80,
+	AvifSpeed:                      5,
 	FormatQuality:                  map[imageType]int{imageTypeAVIF: 50},
 	StripMetadata:                  true,
 	StripColorProfile:              true,
@@ -380,6 +382,7 @@ func configure() error {
 
 	strSliceEnvConfig(&conf.AllowedSources, "IMGPROXY_ALLOWED_SOURCES")
 
+	intEnvConfig(&conf.AvifSpeed, "IMGPROXY_AVIF_SPEED")
 	boolEnvConfig(&conf.JpegProgressive, "IMGPROXY_JPEG_PROGRESSIVE")
 	boolEnvConfig(&conf.PngInterlaced, "IMGPROXY_PNG_INTERLACED")
 	boolEnvConfig(&conf.PngQuantize, "IMGPROXY_PNG_QUANTIZE")
@@ -559,6 +562,12 @@ func configure() error {
 		return fmt.Errorf("Quality can't be greater than 100, now - %d\n", conf.Quality)
 	}
 
+	if conf.AvifSpeed <= 0 {
+		return fmt.Errorf("Avif speed should be greater than 0, now - %d\n", conf.AvifSpeed)
+	} else if conf.AvifSpeed > 8 {
+		return fmt.Errorf("Avif speed can't be greater than 8, now - %d\n", conf.AvifSpeed)
+	}
+
 	if conf.GZipCompression < 0 {
 		return fmt.Errorf("GZip compression should be greater than or equal to 0, now - %d\n", conf.GZipCompression)
 	} else if conf.GZipCompression > 9 {

+ 1 - 0
docs/configuration.md

@@ -130,6 +130,7 @@ imgproxy can use the `Accept` HTTP header to detect if the browser supports AVIF
 * `IMGPROXY_ENFORCE_WEBP`: enables WebP support detection and enforces WebP usage. If the browser supports WebP, it will be used as resulting format even if another extension is specified in the imgproxy URL.
 * `IMGPROXY_ENABLE_AVIF_DETECTION`: enables AVIF support detection. When the file extension is omitted in the imgproxy URL and browser supports AVIF, imgproxy will use it as the resulting format;
 * `IMGPROXY_ENFORCE_AVIF`: enables AVIF support detection and enforces AVIF usage. If the browser supports AVIF, it will be used as resulting format even if another extension is specified in the imgproxy URL.
+* `IMGPROXY_AVIF_SPEED`: controls the CPU effort spent improving compression. 0 slowest - 8 fastest. Default: `5`;
 
 **📝Note:** imgproxy prefers AVIF over WebP. This means that if both AVIF and WebP detection/enforcement are enabled and the browser supports both of them, AVIF will be used.
 

+ 5 - 0
docs/image_formats_support.md

@@ -7,6 +7,7 @@ At the moment, imgproxy supports only the most popular image formats:
 | PNG    | `png`     | Yes    | Yes    |
 | JPEG   | `jpg`     | Yes    | Yes    |
 | WebP   | `webp`    | Yes    | Yes    |
+| AVIF   | `avif`    | Yes    | Yes    |
 | GIF    | `gif`     | Yes    | Yes    |
 | ICO    | `ico`     | Yes    | Yes    |
 | SVG    | `svg`     | Yes    | [See notes](#svg-support) |
@@ -39,6 +40,10 @@ imgproxy reads some amount of bytes to check if the source image is SVG. By defa
 
 imgproxy supports HEIC only when using libvips 8.8.0+. Official imgproxy Docker image supports HEIC out of the box.
 
+## AVIF support
+
+imgproxy supports AVIF only when using libvips 8.9.0+ with compiled support for libheif + its supported encoder (rav1e, aom). Official imgproxy Docker image supports AVIF out of the box.
+
 ## BMP support
 
 imgproxy supports BMP only when using libvips 8.7.0+ compiled with ImageMagick support. Official imgproxy Docker image supports ICO out of the box.

+ 16 - 2
vips.c

@@ -37,6 +37,11 @@
 #define VIPS_SUPPORT_AVIF \
   (VIPS_MAJOR_VERSION > 8 || (VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION >= 9))
 
+#define VIPS_SUPPORT_AVIF_SPEED \
+  (VIPS_MAJOR_VERSION > 8 || \
+    (VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION > 10) || \
+    (VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION >= 10 && VIPS_MICRO_VERSION >= 2))
+
 #define VIPS_SUPPORT_COMPOSITE \
   (VIPS_MAJOR_VERSION > 8 || (VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION >= 6))
 
@@ -258,6 +263,11 @@ vips_support_webp_animation() {
   return VIPS_SUPPORT_WEBP_ANIMATION;
 }
 
+gboolean
+vips_support_avif_speed() {
+  return VIPS_SUPPORT_AVIF_SPEED;
+}
+
 gboolean
 vips_is_animated(VipsImage * in) {
   return( vips_image_get_typeof(in, "page-height") != G_TYPE_INVALID &&
@@ -703,9 +713,13 @@ vips_tiffsave_go(VipsImage *in, void **buf, size_t *len, int quality) {
 }
 
 int
-vips_avifsave_go(VipsImage *in, void **buf, size_t *len, int quality) {
+vips_avifsave_go(VipsImage *in, void **buf, size_t *len, int quality, int speed) {
 #if VIPS_SUPPORT_AVIF
-  return vips_heifsave_buffer(in, buf, len, "Q", quality, "compression", VIPS_FOREIGN_HEIF_COMPRESSION_AV1, NULL);
+  #if VIPS_SUPPORT_AVIF_SPEED
+    return vips_heifsave_buffer(in, buf, len, "Q", quality, "compression", VIPS_FOREIGN_HEIF_COMPRESSION_AV1, "speed", speed, NULL);
+  #else
+    return vips_heifsave_buffer(in, buf, len, "Q", quality, "compression", VIPS_FOREIGN_HEIF_COMPRESSION_AV1, NULL);
+  #endif
 #else
   vips_error("vips_avifsave_go", "Saving AVIF is not supported (libvips 8.9+ reuired)");
   return 1;

+ 3 - 2
vips.go

@@ -36,6 +36,7 @@ var vipsConf struct {
 	PngInterlaced         C.int
 	PngQuantize           C.int
 	PngQuantizationColors C.int
+	AvifSpeed             C.int
 	WatermarkOpacity      C.double
 }
 
@@ -87,7 +88,7 @@ func initVips() error {
 	}
 
 	vipsConf.PngQuantizationColors = C.int(conf.PngQuantizationColors)
-
+	vipsConf.AvifSpeed = C.int(conf.AvifSpeed)
 	vipsConf.WatermarkOpacity = C.double(conf.WatermarkOpacity)
 
 	if err := vipsLoadWatermark(); err != nil {
@@ -200,7 +201,7 @@ func (img *vipsImage) Save(imgtype imageType, quality int) ([]byte, context.Canc
 	case imageTypeGIF:
 		err = C.vips_gifsave_go(img.VipsImage, &ptr, &imgsize)
 	case imageTypeAVIF:
-		err = C.vips_avifsave_go(img.VipsImage, &ptr, &imgsize, C.int(quality))
+		err = C.vips_avifsave_go(img.VipsImage, &ptr, &imgsize, C.int(quality), vipsConf.AvifSpeed)
 	case imageTypeBMP:
 		err = C.vips_bmpsave_go(img.VipsImage, &ptr, &imgsize)
 	case imageTypeTIFF:

+ 3 - 1
vips.h

@@ -47,6 +47,8 @@ VipsBandFormat vips_band_format(VipsImage *in);
 gboolean vips_support_webp_animation();
 gboolean vips_is_animated(VipsImage * in);
 
+gboolean vips_support_avif_speed();
+
 int vips_image_get_array_int_go(VipsImage *image, const char *name, int **out, int *n);
 void vips_image_set_array_int_go(VipsImage *image, const char *name, const int *array, int n);
 
@@ -99,7 +101,7 @@ int vips_jpegsave_go(VipsImage *in, void **buf, size_t *len, int quality, int in
 int vips_pngsave_go(VipsImage *in, void **buf, size_t *len, int interlace, int quantize, int colors);
 int vips_webpsave_go(VipsImage *in, void **buf, size_t *len, int quality);
 int vips_gifsave_go(VipsImage *in, void **buf, size_t *len);
-int vips_avifsave_go(VipsImage *in, void **buf, size_t *len, int quality);
+int vips_avifsave_go(VipsImage *in, void **buf, size_t *len, int quality, int speed);
 int vips_bmpsave_go(VipsImage *in, void **buf, size_t *len);
 int vips_tiffsave_go(VipsImage *in, void **buf, size_t *len, int quality);