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:
parent
3fb3a327a3
commit
f515623f3a
80
process.go
80
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 {
|
||||
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
47
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 );
|
||||
|
7
vips.h
7
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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user