1
0
DarthSim 6 жил өмнө
parent
commit
f515623f3a
3 өөрчлөгдсөн 89 нэмэгдсэн , 43 устгасан
  1. 54 24
      process.go
  2. 30 17
      vips.c
  3. 5 2
      vips.h

+ 54 - 24
process.go

@@ -302,7 +302,7 @@ func transformImage(ctx context.Context, img **C.VipsImage, data []byte, po *pro
 	if scale != 1 && data != nil && canScaleOnLoad(imgtype, scale) {
 		if imgtype == imageTypeWEBP || imgtype == imageTypeSVG {
 			// Do some scale-on-load
-			if tmp, err := vipsLoadImage(data, imgtype, 1, scale, false); err == nil {
+			if tmp, err := vipsLoadImage(data, imgtype, 1, scale, 1); err == nil {
 				C.swap_and_clear(img, tmp)
 			} else {
 				return err
@@ -310,7 +310,7 @@ func transformImage(ctx context.Context, img **C.VipsImage, data []byte, po *pro
 		} else if imgtype == imageTypeJPEG {
 			// Do some shrink-on-load
 			if shrink := calcJpegShink(scale, imgtype); shrink != 1 {
-				if tmp, err := vipsLoadImage(data, imgtype, shrink, 1.0, false); err == nil {
+				if tmp, err := vipsLoadImage(data, imgtype, shrink, 1.0, 1); err == nil {
 					C.swap_and_clear(img, tmp)
 				} else {
 					return err
@@ -473,20 +473,44 @@ func transformImage(ctx context.Context, img **C.VipsImage, data []byte, po *pro
 	return vipsFixColourspace(img)
 }
 
-func transformGif(ctx context.Context, img **C.VipsImage, po *processingOptions) error {
+func transformAnimated(ctx context.Context, img **C.VipsImage, data []byte, po *processingOptions, imgtype imageType) error {
 	imgWidth := int((*img).Xsize)
 	imgHeight := int((*img).Ysize)
 
-	// Double check dimensions because gif may have many frames
-	if err := checkDimensions(imgWidth, imgHeight); err != nil {
+	frameHeight, err := vipsGetInt(*img, "page-height")
+	if err != nil {
 		return err
 	}
 
-	frameHeight, err := vipsGetInt(*img, "page-height")
-	if err != nil {
+	framesCount := minInt(imgHeight/frameHeight, conf.MaxGifFrames)
+
+	// Double check dimensions because animated image has many frames
+	if err := checkDimensions(imgWidth, frameHeight*framesCount); err != nil {
 		return err
 	}
 
+	// Vips 8.8+ supports n-pages and doesn't load the whole animated image on header access
+	if nPages, _ := vipsGetInt(*img, "n-pages"); nPages > 0 {
+		scale := calcScale(imgWidth, frameHeight, po, imgtype)
+
+		if nPages > framesCount || canScaleOnLoad(imgtype, scale) {
+			// Do some scale-on-load
+			if tmp, err := vipsLoadImage(data, imgtype, 1, scale, framesCount); err == nil {
+				C.swap_and_clear(img, tmp)
+			} else {
+				return err
+			}
+		}
+
+		imgWidth = int((*img).Xsize)
+		imgHeight = int((*img).Ysize)
+
+		frameHeight, err = vipsGetInt(*img, "page-height")
+		if err != nil {
+			return err
+		}
+	}
+
 	delay, err := vipsGetInt(*img, "gif-delay")
 	if err != nil {
 		return err
@@ -497,8 +521,6 @@ func transformGif(ctx context.Context, img **C.VipsImage, po *processingOptions)
 		return err
 	}
 
-	framesCount := minInt(imgHeight/frameHeight, conf.MaxGifFrames)
-
 	frames := make([]*C.VipsImage, framesCount)
 	defer func() {
 		for _, frame := range frames {
@@ -517,7 +539,7 @@ func transformGif(ctx context.Context, img **C.VipsImage, po *processingOptions)
 				return err
 			}
 
-			if err := transformImage(ctx, &frame, nil, po, imageTypeGIF); err != nil {
+			if err := transformImage(ctx, &frame, nil, po, imgtype); err != nil {
 				return err
 			}
 
@@ -540,6 +562,7 @@ func transformGif(ctx context.Context, img **C.VipsImage, po *processingOptions)
 	vipsSetInt(*img, "page-height", int(frames[0].Ysize))
 	vipsSetInt(*img, "gif-delay", delay)
 	vipsSetInt(*img, "gif-loop", loop)
+	vipsSetInt(*img, "n-pages", framesCount)
 
 	return nil
 }
@@ -575,14 +598,21 @@ func processImage(ctx context.Context) ([]byte, context.CancelFunc, error) {
 		}
 	}
 
-	img, err := vipsLoadImage(data, imgtype, 1, 1.0, po.Format == imageTypeGIF)
+	animationSupport := conf.MaxGifFrames > 1 && vipsSupportAnimation(imgtype) && vipsSupportAnimation(po.Format)
+
+	pages := 1
+	if animationSupport {
+		pages = -1
+	}
+
+	img, err := vipsLoadImage(data, imgtype, 1, 1.0, pages)
 	if err != nil {
 		return nil, func() {}, err
 	}
 	defer C.clear_image(&img)
 
-	if imgtype == imageTypeGIF && po.Format == imageTypeGIF && vipsIsAnimatedGif(img) {
-		if err := transformGif(ctx, &img, po); err != nil {
+	if animationSupport && vipsIsAnimated(img) {
+		if err := transformAnimated(ctx, &img, data, po, imgtype); err != nil {
 			return nil, func() {}, err
 		}
 	} else {
@@ -615,7 +645,7 @@ func vipsPrepareWatermark() error {
 		return nil
 	}
 
-	watermark, err = vipsLoadImage(data, imgtype, 1, 1.0, false)
+	watermark, err = vipsLoadImage(data, imgtype, 1, 1.0, 1)
 	if err != nil {
 		return err
 	}
@@ -635,7 +665,7 @@ func vipsPrepareWatermark() error {
 	return nil
 }
 
-func vipsLoadImage(data []byte, imgtype imageType, shrink int, scale float64, allPages bool) (*C.VipsImage, error) {
+func vipsLoadImage(data []byte, imgtype imageType, shrink int, scale float64, pages int) (*C.VipsImage, error) {
 	var img *C.VipsImage
 
 	err := C.int(0)
@@ -646,14 +676,9 @@ func vipsLoadImage(data []byte, imgtype imageType, shrink int, scale float64, al
 	case imageTypePNG:
 		err = C.vips_pngload_go(unsafe.Pointer(&data[0]), C.size_t(len(data)), &img)
 	case imageTypeWEBP:
-		err = C.vips_webpload_go(unsafe.Pointer(&data[0]), C.size_t(len(data)), C.double(scale), &img)
+		err = C.vips_webpload_go(unsafe.Pointer(&data[0]), C.size_t(len(data)), C.double(scale), C.int(pages), &img)
 	case imageTypeGIF:
-		pages := C.int(1)
-		if allPages {
-			pages = -1
-		}
-
-		err = C.vips_gifload_go(unsafe.Pointer(&data[0]), C.size_t(len(data)), pages, &img)
+		err = C.vips_gifload_go(unsafe.Pointer(&data[0]), C.size_t(len(data)), C.int(pages), &img)
 	case imageTypeSVG:
 		err = C.vips_svgload_go(unsafe.Pointer(&data[0]), C.size_t(len(data)), C.double(scale), &img)
 	case imageTypeICO:
@@ -717,8 +742,13 @@ func vipsArrayjoin(in []*C.VipsImage, out **C.VipsImage) error {
 	return nil
 }
 
-func vipsIsAnimatedGif(img *C.VipsImage) bool {
-	return C.vips_is_animated_gif(img) > 0
+func vipsSupportAnimation(imgtype imageType) bool {
+	return imgtype == imageTypeGIF ||
+		(imgtype == imageTypeWEBP && C.vips_support_webp_animation() != 0)
+}
+
+func vipsIsAnimated(img *C.VipsImage) bool {
+	return C.vips_is_animated(img) > 0
 }
 
 func vipsImageHasAlpha(img *C.VipsImage) bool {

+ 30 - 17
vips.c

@@ -22,6 +22,12 @@
 #define VIPS_SUPPORT_WEBP_SCALE_ON_LOAD \
   (VIPS_MAJOR_VERSION > 8 || (VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION >= 8))
 
+#define VIPS_SUPPORT_WEBP_ANIMATION \
+  (VIPS_MAJOR_VERSION > 8 || (VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION >= 8))
+
+#define VIPS_SUPPORT_N_PAGES \
+  (VIPS_MAJOR_VERSION > 8 || (VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION >= 8))
+
 #define VIPS_SUPPORT_BUILTIN_ICC \
   (VIPS_MAJOR_VERSION > 8 || (VIPS_MAJOR_VERSION == 8 && VIPS_MINOR_VERSION >= 8))
 
@@ -105,20 +111,21 @@ vips_pngload_go(void *buf, size_t len, VipsImage **out) {
 }
 
 int
-vips_webpload_go(void *buf, size_t len, double scale, VipsImage **out) {
-  if (scale < 1)
-    return vips_webpload_buffer(
-      buf, len, out,
-      "access", VIPS_ACCESS_SEQUENTIAL,
+vips_webpload_go(void *buf, size_t len, double scale, int pages, VipsImage **out) {
+  return vips_webpload_buffer(
+    buf, len, out,
+    "access", VIPS_ACCESS_SEQUENTIAL,
 #if VIPS_SUPPORT_WEBP_SCALE_ON_LOAD
-      "scale", scale,
+    "scale", scale,
 #else
-      "shrink", (int)(1.0 / scale),
+    "shrink", (int)(1.0 / scale),
 #endif
-      NULL
-    );
-
-  return vips_webpload_buffer(buf, len, out, "access", VIPS_ACCESS_SEQUENTIAL, NULL);
+#if VIPS_SUPPORT_WEBP_ANIMATION
+    "n", pages,
+    "page", 0,
+#endif
+    NULL
+  );
 }
 
 int
@@ -141,6 +148,11 @@ vips_svgload_go(void *buf, size_t len, double scale, VipsImage **out) {
   #endif
 }
 
+int
+vips_support_n_pages() {
+  return VIPS_SUPPORT_N_PAGES;
+}
+
 int
 vips_get_exif_orientation(VipsImage *image) {
   const char *orientation;
@@ -155,11 +167,7 @@ vips_get_exif_orientation(VipsImage *image) {
 
 int
 vips_support_smartcrop() {
-#if VIPS_SUPPORT_SMARTCROP
-  return 1;
-#else
-  return 0;
-#endif
+  return VIPS_SUPPORT_SMARTCROP;
 }
 
 VipsBandFormat
@@ -168,7 +176,12 @@ vips_band_format(VipsImage *in) {
 }
 
 gboolean
-vips_is_animated_gif(VipsImage * in) {
+vips_support_webp_animation() {
+  return VIPS_SUPPORT_WEBP_ANIMATION;
+}
+
+gboolean
+vips_is_animated(VipsImage * in) {
   return( vips_image_get_typeof(in, "page-height") != G_TYPE_INVALID &&
           vips_image_get_typeof(in, "gif-delay") != G_TYPE_INVALID &&
           vips_image_get_typeof(in, "gif-loop") != G_TYPE_INVALID );

+ 5 - 2
vips.h

@@ -25,10 +25,12 @@ int vips_type_find_save_go(int imgtype);
 
 int vips_jpegload_go(void *buf, size_t len, int shrink, VipsImage **out);
 int vips_pngload_go(void *buf, size_t len, VipsImage **out);
-int vips_webpload_go(void *buf, size_t len, double scale, VipsImage **out);
+int vips_webpload_go(void *buf, size_t len, double scale, int pages, VipsImage **out);
 int vips_gifload_go(void *buf, size_t len, int pages, VipsImage **out);
 int vips_svgload_go(void *buf, size_t len, double scale, VipsImage **out);
 
+int vips_support_n_pages();
+
 int vips_get_exif_orientation(VipsImage *image);
 void vips_strip_meta(VipsImage *image);
 
@@ -36,7 +38,8 @@ int vips_support_smartcrop();
 
 VipsBandFormat vips_band_format(VipsImage *in);
 
-gboolean vips_is_animated_gif(VipsImage * in);
+gboolean vips_support_webp_animation();
+gboolean vips_is_animated(VipsImage * in);
 gboolean vips_image_hasalpha_go(VipsImage * in);
 
 int vips_copy_go(VipsImage *in, VipsImage **out);