1
0
mirror of https://github.com/imgproxy/imgproxy.git synced 2025-02-07 11:36:25 +02:00

Animated WebP support

This commit is contained in:
DarthSim 2019-06-03 16:53:47 +06:00
parent 3fb3a327a3
commit f515623f3a
3 changed files with 90 additions and 44 deletions

View File

@ -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 {
return err
}
frameHeight, err := vipsGetInt(*img, "page-height")
if err != nil {
return err
}
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 {

47
vips.c
View File

@ -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 );

7
vips.h
View File

@ -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);