ソースを参照

Fix animations loops and delays

DarthSim 4 年 前
コミット
bad20a3f02
4 ファイル変更104 行追加5 行削除
  1. 34 5
      process.go
  2. 20 0
      vips.c
  3. 47 0
      vips.go
  4. 3 0
      vips.h

+ 34 - 5
process.go

@@ -595,19 +595,30 @@ func transformAnimated(ctx context.Context, img *vipsImage, data []byte, po *pro
 	}
 
 	// Vips 8.8+ supports n-pages and doesn't load the whole animated image on header access
-	if nPages, _ := img.GetInt("n-pages"); nPages > framesCount {
+	if nPages, _ := img.GetIntDefault("n-pages", 0); nPages > framesCount {
 		// Load only the needed frames
 		if err = img.Load(data, imgtype, 1, 1.0, framesCount); err != nil {
 			return err
 		}
 	}
 
-	delay, err := img.GetInt("gif-delay")
+	delay, err := img.GetIntSliceDefault("delay", nil)
 	if err != nil {
 		return err
 	}
 
-	loop, err := img.GetInt("gif-loop")
+	loop, err := img.GetIntDefault("loop", 0)
+	if err != nil {
+		return err
+	}
+
+	// Legacy fields
+	// TODO: remove this in major update
+	gifLoop, err := img.GetIntDefault("gif-loop", -1)
+	if err != nil {
+		return err
+	}
+	gifDelay, err := img.GetIntDefault("gif-delay", -1)
 	if err != nil {
 		return err
 	}
@@ -661,11 +672,29 @@ func transformAnimated(ctx context.Context, img *vipsImage, data []byte, po *pro
 		return err
 	}
 
+	if len(delay) == 0 {
+		delay = make([]int, framesCount)
+		for i := range delay {
+			delay[i] = 40
+		}
+	} else if len(delay) > framesCount {
+		delay = delay[:framesCount]
+	}
+
 	img.SetInt("page-height", frames[0].Height())
-	img.SetInt("gif-delay", delay)
-	img.SetInt("gif-loop", loop)
+	img.SetIntSlice("delay", delay)
+	img.SetInt("loop", loop)
 	img.SetInt("n-pages", framesCount)
 
+	// Legacy fields
+	// TODO: remove this in major update
+	if gifLoop >= 0 {
+		img.SetInt("gif-loop", gifLoop)
+	}
+	if gifDelay >= 0 {
+		img.SetInt("gif-delay", gifDelay)
+	}
+
 	return nil
 }
 

+ 20 - 0
vips.c

@@ -28,6 +28,9 @@
 #define VIPS_SUPPORT_WEBP_ANIMATION \
   (VIPS_MAJOR_VERSION > 8 || (VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION >= 8))
 
+#define VIPS_SUPPORT_ARRAY_HEADERS \
+  (VIPS_MAJOR_VERSION > 8 || (VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION >= 9))
+
 #define VIPS_SUPPORT_HEIF \
   (VIPS_MAJOR_VERSION > 8 || (VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION >= 8))
 
@@ -245,6 +248,23 @@ vips_is_animated(VipsImage * in) {
           vips_image_get_typeof(in, "gif-loop") != G_TYPE_INVALID );
 }
 
+int
+vips_image_get_array_int_go(VipsImage *image, const char *name, int **out, int *n) {
+#if VIPS_SUPPORT_ARRAY_HEADERS
+  return vips_image_get_array_int(image, name, out, n);
+#else
+  vips_error("vips_image_get_array_int_go", "Array headers are not supported (libvips 8.9+ reuired)");
+  return 1;
+#endif
+}
+
+void
+vips_image_set_array_int_go(VipsImage *image, const char *name, const int *array, int n) {
+#if VIPS_SUPPORT_ARRAY_HEADERS
+  vips_image_set_array_int(image, name, array, n);
+#endif
+}
+
 gboolean
 vips_image_hasalpha_go(VipsImage * in) {
 #if VIPS_SUPPORT_HASALPHA

+ 47 - 0
vips.go

@@ -13,6 +13,7 @@ import (
 	"encoding/binary"
 	"errors"
 	"fmt"
+	"math"
 	"os"
 	"runtime"
 	"unsafe"
@@ -330,10 +331,56 @@ func (img *vipsImage) GetInt(name string) (int, error) {
 	return int(i), nil
 }
 
+func (img *vipsImage) GetIntDefault(name string, def int) (int, error) {
+	if C.vips_image_get_typeof(img.VipsImage, cachedCString(name)) == 0 {
+		return def, nil
+	}
+
+	return img.GetInt(name)
+}
+
+func (img *vipsImage) GetIntSlice(name string) ([]int, error) {
+	var ptr unsafe.Pointer
+	size := C.int(0)
+
+	if C.vips_image_get_array_int_go(img.VipsImage, cachedCString(name), (**C.int)(unsafe.Pointer(&ptr)), &size) != 0 {
+		return nil, vipsError()
+	}
+
+	if size == 0 {
+		return []int{}, nil
+	}
+
+	cOut := (*[math.MaxInt32]C.int)(ptr)[:int(size):int(size)]
+	out := make([]int, int(size))
+
+	for i, el := range cOut {
+		out[i] = int(el)
+	}
+
+	return out, nil
+}
+
+func (img *vipsImage) GetIntSliceDefault(name string, def []int) ([]int, error) {
+	if C.vips_image_get_typeof(img.VipsImage, cachedCString(name)) == 0 {
+		return def, nil
+	}
+
+	return img.GetIntSlice(name)
+}
+
 func (img *vipsImage) SetInt(name string, value int) {
 	C.vips_image_set_int(img.VipsImage, cachedCString(name), C.int(value))
 }
 
+func (img *vipsImage) SetIntSlice(name string, value []int) {
+	in := make([]C.int, len(value))
+	for i, el := range value {
+		in[i] = C.int(el)
+	}
+	C.vips_image_set_array_int_go(img.VipsImage, cachedCString(name), &in[0], C.int(len(value)))
+}
+
 func (img *vipsImage) CastUchar() error {
 	var tmp *C.VipsImage
 

+ 3 - 0
vips.h

@@ -47,6 +47,9 @@ VipsBandFormat vips_band_format(VipsImage *in);
 gboolean vips_support_webp_animation();
 gboolean vips_is_animated(VipsImage * in);
 
+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);
+
 gboolean vips_image_hasalpha_go(VipsImage * in);
 int vips_addalpha_go(VipsImage *in, VipsImage **out);