Bladeren bron

Better animation detection

DarthSim 2 jaren geleden
bovenliggende
commit
8a536d69a3
2 gewijzigde bestanden met toevoegingen van 48 en 44 verwijderingen
  1. 40 41
      processing/processing.go
  2. 8 3
      vips/vips.c

+ 40 - 41
processing/processing.go

@@ -42,20 +42,6 @@ func imageTypeGoodForWeb(imgtype imagetype.Type) bool {
 		imgtype != imagetype.BMP
 }
 
-// src  - the source image format
-// dst  - what the user specified
-// want - what we want switch to
-func canSwitchFormat(src, dst, want imagetype.Type) bool {
-	// If the format we want is not supported, we can't switch to it anyway
-	return vips.SupportsSave(want) &&
-		// if src format does't support animation, we can switch to whatever we want
-		(!src.SupportsAnimation() ||
-			// if user specified the format and it doesn't support animation, we can switch to whatever we want
-			(dst != imagetype.Unknown && !dst.SupportsAnimation()) ||
-			// if the format we want supports animation, we can switch in any case
-			want.SupportsAnimation())
-}
-
 func canFitToBytes(imgtype imagetype.Type) bool {
 	switch imgtype {
 	case imagetype.JPEG, imagetype.WEBP, imagetype.AVIF, imagetype.TIFF:
@@ -96,7 +82,7 @@ func transformAnimated(ctx context.Context, img *vips.Image, po *options.Process
 	}
 
 	// Vips 8.8+ supports n-pages and doesn't load the whole animated image on header access
-	if nPages, _ := img.GetIntDefault("n-pages", 0); nPages > framesCount {
+	if nPages, _ := img.GetIntDefault("n-pages", 1); nPages > framesCount {
 		// Load only the needed frames
 		if err = img.Load(imgdata, 1, 1.0, framesCount); err != nil {
 			return err
@@ -117,7 +103,7 @@ func transformAnimated(ctx context.Context, img *vips.Image, po *options.Process
 	po.Watermark.Enabled = false
 	defer func() { po.Watermark.Enabled = watermarkEnabled }()
 
-	frames := make([]*vips.Image, framesCount)
+	frames := make([]*vips.Image, 0, framesCount)
 	defer func() {
 		for _, frame := range frames {
 			if frame != nil {
@@ -133,7 +119,7 @@ func transformAnimated(ctx context.Context, img *vips.Image, po *options.Process
 			return err
 		}
 
-		frames[i] = frame
+		frames = append(frames, frame)
 
 		if err = mainPipeline.Run(ctx, frame, po, nil); err != nil {
 			return err
@@ -207,29 +193,10 @@ func ProcessImage(ctx context.Context, imgdata *imagedata.ImageData, po *options
 
 	defer vips.Cleanup()
 
-	switch {
-	case po.Format == imagetype.Unknown:
-		switch {
-		case po.PreferAvif && canSwitchFormat(imgdata.Type, imagetype.Unknown, imagetype.AVIF):
-			po.Format = imagetype.AVIF
-		case po.PreferWebP && canSwitchFormat(imgdata.Type, imagetype.Unknown, imagetype.WEBP):
-			po.Format = imagetype.WEBP
-		case vips.SupportsSave(imgdata.Type) && imageTypeGoodForWeb(imgdata.Type):
-			po.Format = imgdata.Type
-		default:
-			po.Format = imagetype.JPEG
-		}
-	case po.EnforceAvif && canSwitchFormat(imgdata.Type, po.Format, imagetype.AVIF):
-		po.Format = imagetype.AVIF
-	case po.EnforceWebP && canSwitchFormat(imgdata.Type, po.Format, imagetype.WEBP):
-		po.Format = imagetype.WEBP
-	}
-
-	if !vips.SupportsSave(po.Format) {
-		return nil, fmt.Errorf("Can't save %s, probably not supported by your libvips", po.Format)
-	}
-
-	animationSupport := config.MaxAnimationFrames > 1 && imgdata.Type.SupportsAnimation() && po.Format.SupportsAnimation()
+	animationSupport :=
+		config.MaxAnimationFrames > 1 &&
+			imgdata.Type.SupportsAnimation() &&
+			(po.Format == imagetype.Unknown || po.Format.SupportsAnimation())
 
 	pages := 1
 	if animationSupport {
@@ -251,11 +218,43 @@ func ProcessImage(ctx context.Context, imgdata *imagedata.ImageData, po *options
 
 	originWidth, originHeight := getImageSize(img)
 
-	if animationSupport && img.IsAnimated() {
+	animated := img.IsAnimated()
+
+	switch {
+	case po.Format == imagetype.Unknown:
+		switch {
+		case po.PreferAvif && !animated:
+			po.Format = imagetype.AVIF
+		case po.PreferWebP:
+			po.Format = imagetype.WEBP
+		case vips.SupportsSave(imgdata.Type) && imageTypeGoodForWeb(imgdata.Type):
+			po.Format = imgdata.Type
+		default:
+			po.Format = imagetype.JPEG
+		}
+	case po.EnforceAvif && !animated:
+		po.Format = imagetype.AVIF
+	case po.EnforceWebP:
+		po.Format = imagetype.WEBP
+	}
+
+	if !vips.SupportsSave(po.Format) {
+		return nil, fmt.Errorf("Can't save %s, probably not supported by your libvips", po.Format)
+	}
+
+	if po.Format.SupportsAnimation() && animated {
 		if err := transformAnimated(ctx, img, po, imgdata); err != nil {
 			return nil, err
 		}
 	} else {
+		if animated {
+			// We loaded animated image but the resulting format doesn't support
+			// animations, so we need to reload image as not animated
+			if err := img.Load(imgdata, 1, 1.0, 1); err != nil {
+				return nil, err
+			}
+		}
+
 		if err := mainPipeline.Run(ctx, img, po, imgdata); err != nil {
 			return nil, err
 		}

+ 8 - 3
vips/vips.c

@@ -139,9 +139,14 @@ vips_band_format(VipsImage *in) {
 
 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 );
+  int n_pages;
+
+  return( vips_image_get_typeof(in, "delay") != G_TYPE_INVALID &&
+          vips_image_get_typeof(in, "loop") != G_TYPE_INVALID &&
+          vips_image_get_typeof(in, "page-height") == G_TYPE_INT &&
+          vips_image_get_typeof(in, "n-pages") == G_TYPE_INT &&
+          vips_image_get_int(in, "n-pages", &n_pages) == 0 &&
+          n_pages > 1 );
 }
 
 int