mirror of
				https://github.com/imgproxy/imgproxy.git
				synced 2025-10-30 23:08:02 +02:00 
			
		
		
		
	Use heic/avif embedded thumbnails
This commit is contained in:
		| @@ -1,9 +1,12 @@ | ||||
| # Changelog | ||||
|  | ||||
| ## [Unreleased] | ||||
| ## Add | ||||
| ### Add | ||||
| - Add support of RLE-encoded BMP. | ||||
|  | ||||
| ### Change | ||||
| - Use thumbnail embedded to HEIC/AVIF if its size is larger than or equal to the requested. | ||||
|  | ||||
| ## [3.4.0] - 2022-04-07 | ||||
| ### Add | ||||
| - Add `IMGPROXY_FALLBACK_IMAGE_TTL` config. | ||||
|   | ||||
| @@ -130,3 +130,7 @@ func (it Type) SupportsColourProfile() bool { | ||||
| 		it == WEBP || | ||||
| 		it == AVIF | ||||
| } | ||||
|  | ||||
| func (it Type) SupportsThumbnail() bool { | ||||
| 	return it == HEIC || it == AVIF | ||||
| } | ||||
|   | ||||
| @@ -11,8 +11,12 @@ import ( | ||||
| 	"github.com/imgproxy/imgproxy/v3/vips" | ||||
| ) | ||||
|  | ||||
| func canScaleOnLoad(imgtype imagetype.Type, scale float64) bool { | ||||
| 	if imgtype == imagetype.SVG { | ||||
| func canScaleOnLoad(pctx *pipelineContext, imgdata *imagedata.ImageData, scale float64) bool { | ||||
| 	if imgdata == nil || pctx.trimmed || scale == 1 { | ||||
| 		return false | ||||
| 	} | ||||
|  | ||||
| 	if imgdata.Type == imagetype.SVG { | ||||
| 		return true | ||||
| 	} | ||||
|  | ||||
| @@ -20,7 +24,10 @@ func canScaleOnLoad(imgtype imagetype.Type, scale float64) bool { | ||||
| 		return false | ||||
| 	} | ||||
|  | ||||
| 	return imgtype == imagetype.JPEG || imgtype == imagetype.WEBP | ||||
| 	return imgdata.Type == imagetype.JPEG || | ||||
| 		imgdata.Type == imagetype.WEBP || | ||||
| 		imgdata.Type == imagetype.HEIC || | ||||
| 		imgdata.Type == imagetype.AVIF | ||||
| } | ||||
|  | ||||
| func calcJpegShink(scale float64, imgtype imagetype.Type) int { | ||||
| @@ -41,23 +48,45 @@ func calcJpegShink(scale float64, imgtype imagetype.Type) int { | ||||
| func scaleOnLoad(pctx *pipelineContext, img *vips.Image, po *options.ProcessingOptions, imgdata *imagedata.ImageData) error { | ||||
| 	prescale := math.Max(pctx.wscale, pctx.hscale) | ||||
|  | ||||
| 	if pctx.trimmed || prescale == 1 || imgdata == nil || !canScaleOnLoad(pctx.imgtype, prescale) { | ||||
| 	if !canScaleOnLoad(pctx, imgdata, prescale) { | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
| 	jpegShrink := calcJpegShink(prescale, pctx.imgtype) | ||||
| 	var newWidth, newHeight int | ||||
|  | ||||
| 	if pctx.imgtype == imagetype.JPEG && jpegShrink == 1 { | ||||
| 		return nil | ||||
| 	} | ||||
| 	if imgdata.Type.SupportsThumbnail() { | ||||
| 		thumbnail := new(vips.Image) | ||||
| 		defer thumbnail.Clear() | ||||
|  | ||||
| 	if err := img.Load(imgdata, jpegShrink, prescale, 1); err != nil { | ||||
| 		return err | ||||
| 		if err := thumbnail.LoadThumbnail(imgdata); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
|  | ||||
| 		angle, flip := 0, false | ||||
| 		newWidth, newHeight, angle, flip = extractMeta(thumbnail, po.Rotate, po.AutoRotate) | ||||
|  | ||||
| 		if newWidth >= pctx.srcWidth || float64(newWidth)/float64(pctx.srcWidth) < prescale { | ||||
| 			return nil | ||||
| 		} | ||||
|  | ||||
| 		img.Swap(thumbnail) | ||||
| 		pctx.angle = angle | ||||
| 		pctx.flip = flip | ||||
| 	} else { | ||||
| 		jpegShrink := calcJpegShink(prescale, pctx.imgtype) | ||||
|  | ||||
| 		if pctx.imgtype == imagetype.JPEG && jpegShrink == 1 { | ||||
| 			return nil | ||||
| 		} | ||||
|  | ||||
| 		if err := img.Load(imgdata, jpegShrink, prescale, 1); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
|  | ||||
| 		newWidth, newHeight, _, _ = extractMeta(img, po.Rotate, po.AutoRotate) | ||||
| 	} | ||||
|  | ||||
| 	// Update scales after scale-on-load | ||||
| 	newWidth, newHeight, _, _ := extractMeta(img, po.Rotate, po.AutoRotate) | ||||
|  | ||||
| 	wpreshrink := float64(pctx.srcWidth) / float64(newWidth) | ||||
| 	hpreshrink := float64(pctx.srcHeight) / float64(newHeight) | ||||
|  | ||||
|   | ||||
| @@ -82,8 +82,13 @@ vips_svgload_go(void *buf, size_t len, double scale, VipsImage **out) { | ||||
| } | ||||
|  | ||||
| int | ||||
| vips_heifload_go(void *buf, size_t len, VipsImage **out) { | ||||
|   return vips_heifload_buffer(buf, len, out, "access", VIPS_ACCESS_SEQUENTIAL, NULL); | ||||
| vips_heifload_go(void *buf, size_t len, VipsImage **out, int thumbnail) { | ||||
|   return vips_heifload_buffer( | ||||
|     buf, len, out, | ||||
|     "access", VIPS_ACCESS_SEQUENTIAL, | ||||
|     "thumbnail", thumbnail, | ||||
|     NULL | ||||
|   ); | ||||
| } | ||||
|  | ||||
| int | ||||
|   | ||||
							
								
								
									
										25
									
								
								vips/vips.go
									
									
									
									
									
								
							
							
						
						
									
										25
									
								
								vips/vips.go
									
									
									
									
									
								
							| @@ -229,7 +229,7 @@ func (img *Image) Load(imgdata *imagedata.ImageData, shrink int, scale float64, | ||||
| 	case imagetype.SVG: | ||||
| 		err = C.vips_svgload_go(data, dataSize, C.double(scale), &tmp) | ||||
| 	case imagetype.HEIC, imagetype.AVIF: | ||||
| 		err = C.vips_heifload_go(data, dataSize, &tmp) | ||||
| 		err = C.vips_heifload_go(data, dataSize, &tmp, C.int(0)) | ||||
| 	case imagetype.TIFF: | ||||
| 		err = C.vips_tiffload_go(data, dataSize, &tmp) | ||||
| 	default: | ||||
| @@ -244,6 +244,25 @@ func (img *Image) Load(imgdata *imagedata.ImageData, shrink int, scale float64, | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (img *Image) LoadThumbnail(imgdata *imagedata.ImageData) error { | ||||
| 	if imgdata.Type != imagetype.HEIC && imgdata.Type != imagetype.AVIF { | ||||
| 		return errors.New("Usupported image type to load thumbnail") | ||||
| 	} | ||||
|  | ||||
| 	var tmp *C.VipsImage | ||||
|  | ||||
| 	data := unsafe.Pointer(&imgdata.Data[0]) | ||||
| 	dataSize := C.size_t(len(imgdata.Data)) | ||||
|  | ||||
| 	if err := C.vips_heifload_go(data, dataSize, &tmp, C.int(1)); err != 0 { | ||||
| 		return Error() | ||||
| 	} | ||||
|  | ||||
| 	C.swap_and_clear(&img.VipsImage, tmp) | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (img *Image) Save(imgtype imagetype.Type, quality int) (*imagedata.ImageData, error) { | ||||
| 	if imgtype == imagetype.ICO { | ||||
| 		return img.saveAsIco() | ||||
| @@ -314,6 +333,10 @@ func (img *Image) Arrayjoin(in []*Image) error { | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (img *Image) Swap(in *Image) { | ||||
| 	img.VipsImage, in.VipsImage = in.VipsImage, img.VipsImage | ||||
| } | ||||
|  | ||||
| func (img *Image) IsAnimated() bool { | ||||
| 	return C.vips_is_animated(img.VipsImage) > 0 | ||||
| } | ||||
|   | ||||
| @@ -19,7 +19,7 @@ int vips_pngload_go(void *buf, size_t len, 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_heifload_go(void *buf, size_t len, VipsImage **out); | ||||
| int vips_heifload_go(void *buf, size_t len, VipsImage **out, int thumbnail); | ||||
| int vips_tiffload_go(void *buf, size_t len, VipsImage **out); | ||||
|  | ||||
| int vips_black_go(VipsImage **out, int width, int height, int bands); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user