davidbyttow / govips

A lightning fast image processing and resizing library for Go
MIT License
1.23k stars 196 forks source link

How to crop animated images #396

Closed david02324 closed 7 months ago

david02324 commented 7 months ago

Govips version 8.10.5 / Debian GNU/Linux 11 (bullseye)

I tried to implement CSS Object-fit spec requirements using govips

image

func vipsCropStyle(originalWidth, originalHeight int, style *Style) (vips.Interesting, vips.Size) {
    switch style.Fit {
    case Cover:
        if originalWidth < style.Size.Width || originalHeight < style.Size.Height {
            return vips.InterestingCentre, vips.SizeUp
        }

        return vips.InterestingCentre, vips.SizeDown
    case Fill:
        return vips.InterestingAll, vips.SizeForce
    case Outside:
        return vips.InterestingAll, vips.SizeUp
    case Contain:
        return vips.InterestingCentre, vips.SizeLast
    }

    return vips.InterestingNone, vips.SizeDown // "inside"
}

and this worked pretty well in most usecases.

But some strange behavior happens when cropping & resizing animated images

Source image

abc

if I try to crop this image with Cover or Contain option, this is the result. (Other options work well)

The following simple code can reproduce the problem.

func TestAnimatedImageCrop(t *testing.T) {
    importParams := vips.NewImportParams()
    importParams.NumPages.Set(-1)
    importParams.FailOnError.Set(false)

    img, e := loadImageFromFile("the-simpson.gif", importParams) // original image size is 320x320
    if e != nil {
        t.Fatal(e)
        return
    }

    if err := img.AutoRotate(); err != nil {
        t.Fatal(err)
        return
    }

    style := &govips.Style{
        Size: &govips.Size{
            Width:  200,
            Height: 200,
        },
        Fit:       govips.Cover,
        ImageType: govips.ImageFormatGIF,
    }
    interesting, scale := vipsCropStyle(img.Width(), img.Height(), style)
    err := img.ThumbnailWithSize(style.Size.Width, style.Size.Height, interesting, scale)
    if err != nil {
        t.Fatal(err)
        return
    }

    buf, _, err := img.ExportGIF(vips.NewGifExportParams())
    if err != nil {
        t.Fatal(err)
        return
    }

    path, err := govips.SaveImageFileFromBuffer(buf, ".gif")
    if err != nil {
        t.Fatal(err)
    }

    fmt.Println(path)
}

How can I crop animated image well? or please let me know if I'm using govips incorrectly or if it's not supported because it's an old version

songjiayang commented 7 months ago

Some code like https://github.com/imagecodex/govips/pull/9