Ver Fonte

Load ICO without imagemagick

DarthSim há 5 anos atrás
pai
commit
a3d894a697
5 ficheiros alterados com 45 adições e 30 exclusões
  1. 7 6
      image_size/ico.go
  2. 38 1
      process.go
  3. 0 12
      vips.c
  4. 0 10
      vips.go
  5. 0 1
      vips.h

+ 7 - 6
image_size/ico.go

@@ -5,7 +5,7 @@ import (
 	"io"
 )
 
-func icoBestSize(r io.Reader) (width, height byte, page uint16, err error) {
+func icoBestSize(r io.Reader) (width, height byte, offset uint32, size uint32, err error) {
 	var tmp [16]byte
 
 	if _, err = io.ReadFull(r, tmp[:6]); err != nil {
@@ -22,20 +22,21 @@ func icoBestSize(r io.Reader) (width, height byte, page uint16, err error) {
 		if tmp[0] > width || tmp[1] > height || tmp[0] == 0 || tmp[1] == 0 {
 			width = tmp[0]
 			height = tmp[1]
-			page = i
+			size = binary.LittleEndian.Uint32(tmp[8:12])
+			offset = binary.LittleEndian.Uint32(tmp[12:16])
 		}
 	}
 
 	return
 }
 
-func BestIcoPage(r io.Reader) (int, error) {
-	_, _, page, err := icoBestSize(r)
-	return int(page), err
+func BestIcoPage(r io.Reader) (int, int, error) {
+	_, _, offset, size, err := icoBestSize(r)
+	return int(offset), int(size), err
 }
 
 func DecodeIcoMeta(r io.Reader) (*Meta, error) {
-	bwidth, bheight, _, err := icoBestSize(r)
+	bwidth, bheight, _, _, err := icoBestSize(r)
 	if err != nil {
 		return nil, err
 	}

+ 38 - 1
process.go

@@ -1,10 +1,13 @@
 package main
 
 import (
+	"bytes"
 	"context"
+	"fmt"
 	"math"
 	"runtime"
 
+	imageSize "github.com/imgproxy/imgproxy/image_size"
 	"golang.org/x/sync/errgroup"
 )
 
@@ -13,7 +16,9 @@ const msgSmartCropNotSupported = "Smart crop is not supported by used version of
 var errConvertingNonSvgToSvg = newError(422, "Converting non-SVG images to SVG is not supported", "Converting non-SVG images to SVG is not supported")
 
 func imageTypeLoadSupport(imgtype imageType) bool {
-	return imgtype == imageTypeSVG || vipsTypeSupportLoad[imgtype]
+	return imgtype == imageTypeSVG ||
+		imgtype == imageTypeICO ||
+		vipsTypeSupportLoad[imgtype]
 }
 
 func imageTypeSaveSupport(imgtype imageType) bool {
@@ -541,6 +546,29 @@ func transformAnimated(ctx context.Context, img *vipsImage, data []byte, po *pro
 	return nil
 }
 
+func getIcoData(imgdata *imageData) (*imageData, error) {
+	offset, size, err := imageSize.BestIcoPage(bytes.NewBuffer(imgdata.Data))
+	if err != nil {
+		return nil, err
+	}
+
+	data := imgdata.Data[offset : offset+size]
+
+	meta, err := imageSize.DecodeMeta(bytes.NewBuffer(data))
+	if err != nil {
+		return nil, err
+	}
+
+	if imgtype, ok := imageTypes[meta.Format]; ok && vipsTypeSupportLoad[imgtype] {
+		return &imageData{
+			Data: data,
+			Type: imgtype,
+		}, nil
+	}
+
+	return nil, fmt.Errorf("Can't load %s from ICO", meta.Format)
+}
+
 func processImage(ctx context.Context) ([]byte, context.CancelFunc, error) {
 	runtime.LockOSThread()
 	defer runtime.UnlockOSThread()
@@ -584,6 +612,15 @@ func processImage(ctx context.Context) ([]byte, context.CancelFunc, error) {
 		return []byte{}, func() {}, errSourceImageTypeNotSupported
 	}
 
+	if imgdata.Type == imageTypeICO {
+		icodata, err := getIcoData(imgdata)
+		if err != nil {
+			return nil, func() {}, err
+		}
+
+		imgdata = icodata
+	}
+
 	if !vipsSupportSmartcrop {
 		if po.Gravity.Type == gravitySmart {
 			logWarning(msgSmartCropNotSupported)

+ 0 - 12
vips.c

@@ -80,8 +80,6 @@ vips_type_find_load_go(int imgtype) {
     return vips_type_find("VipsOperation", "gifload_buffer");
   case (SVG):
     return vips_type_find("VipsOperation", "svgload_buffer");
-  case (ICO):
-    return vips_type_find("VipsOperation", "magickload_buffer");
   case (HEIC):
     return vips_type_find("VipsOperation", "heifload_buffer");
   case (BMP):
@@ -167,16 +165,6 @@ vips_svgload_go(void *buf, size_t len, double scale, VipsImage **out) {
   #endif
 }
 
-int
-vips_icoload_go(void *buf, size_t len, int page, VipsImage **out) {
-  #if VIPS_SUPPORT_MAGICK
-    return vips_magickload_buffer(buf, len, out, "access", VIPS_ACCESS_SEQUENTIAL, "page", page, NULL);
-  #else
-    vips_error("vips_icoload_go", "Loading ICO is not supported (libvips 8.7+ reuired)");
-    return 1;
-  #endif
-}
-
 int
 vips_heifload_go(void *buf, size_t len, VipsImage **out) {
 #if VIPS_SUPPORT_HEIF

+ 0 - 10
vips.go

@@ -8,15 +8,12 @@ package main
 */
 import "C"
 import (
-	"bytes"
 	"context"
 	"math"
 	"os"
 	"runtime"
 	"time"
 	"unsafe"
-
-	imageSize "github.com/imgproxy/imgproxy/image_size"
 )
 
 type vipsImage struct {
@@ -157,13 +154,6 @@ func (img *vipsImage) Load(data []byte, imgtype imageType, shrink int, scale flo
 		err = C.vips_gifload_go(unsafe.Pointer(&data[0]), C.size_t(len(data)), C.int(pages), &tmp)
 	case imageTypeSVG:
 		err = C.vips_svgload_go(unsafe.Pointer(&data[0]), C.size_t(len(data)), C.double(scale), &tmp)
-	case imageTypeICO:
-		bestPage, ierr := imageSize.BestIcoPage(bytes.NewBuffer(data))
-		if ierr != nil {
-			logWarning(ierr.Error())
-		}
-
-		err = C.vips_icoload_go(unsafe.Pointer(&data[0]), C.size_t(len(data)), C.int(bestPage), &tmp)
 	case imageTypeHEIC:
 		err = C.vips_heifload_go(unsafe.Pointer(&data[0]), C.size_t(len(data)), &tmp)
 	case imageTypeBMP:

+ 0 - 1
vips.h

@@ -32,7 +32,6 @@ 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_icoload_go(void *buf, size_t len, int page, VipsImage **out);
 int vips_heifload_go(void *buf, size_t len, VipsImage **out);
 int vips_bmpload_go(void *buf, size_t len, VipsImage **out);
 int vips_tiffload_go(void *buf, size_t len, VipsImage **out);