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

Load ICO without imagemagick

This commit is contained in:
DarthSim 2019-10-03 21:43:33 +06:00
parent bda7e1e53d
commit a3d894a697
5 changed files with 45 additions and 30 deletions

View File

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

View File

@ -1,10 +1,13 @@
package main package main
import ( import (
"bytes"
"context" "context"
"fmt"
"math" "math"
"runtime" "runtime"
imageSize "github.com/imgproxy/imgproxy/image_size"
"golang.org/x/sync/errgroup" "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") 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 { func imageTypeLoadSupport(imgtype imageType) bool {
return imgtype == imageTypeSVG || vipsTypeSupportLoad[imgtype] return imgtype == imageTypeSVG ||
imgtype == imageTypeICO ||
vipsTypeSupportLoad[imgtype]
} }
func imageTypeSaveSupport(imgtype imageType) bool { func imageTypeSaveSupport(imgtype imageType) bool {
@ -541,6 +546,29 @@ func transformAnimated(ctx context.Context, img *vipsImage, data []byte, po *pro
return nil 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) { func processImage(ctx context.Context) ([]byte, context.CancelFunc, error) {
runtime.LockOSThread() runtime.LockOSThread()
defer runtime.UnlockOSThread() defer runtime.UnlockOSThread()
@ -584,6 +612,15 @@ func processImage(ctx context.Context) ([]byte, context.CancelFunc, error) {
return []byte{}, func() {}, errSourceImageTypeNotSupported return []byte{}, func() {}, errSourceImageTypeNotSupported
} }
if imgdata.Type == imageTypeICO {
icodata, err := getIcoData(imgdata)
if err != nil {
return nil, func() {}, err
}
imgdata = icodata
}
if !vipsSupportSmartcrop { if !vipsSupportSmartcrop {
if po.Gravity.Type == gravitySmart { if po.Gravity.Type == gravitySmart {
logWarning(msgSmartCropNotSupported) logWarning(msgSmartCropNotSupported)

12
vips.c
View File

@ -80,8 +80,6 @@ vips_type_find_load_go(int imgtype) {
return vips_type_find("VipsOperation", "gifload_buffer"); return vips_type_find("VipsOperation", "gifload_buffer");
case (SVG): case (SVG):
return vips_type_find("VipsOperation", "svgload_buffer"); return vips_type_find("VipsOperation", "svgload_buffer");
case (ICO):
return vips_type_find("VipsOperation", "magickload_buffer");
case (HEIC): case (HEIC):
return vips_type_find("VipsOperation", "heifload_buffer"); return vips_type_find("VipsOperation", "heifload_buffer");
case (BMP): case (BMP):
@ -167,16 +165,6 @@ vips_svgload_go(void *buf, size_t len, double scale, VipsImage **out) {
#endif #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 int
vips_heifload_go(void *buf, size_t len, VipsImage **out) { vips_heifload_go(void *buf, size_t len, VipsImage **out) {
#if VIPS_SUPPORT_HEIF #if VIPS_SUPPORT_HEIF

10
vips.go
View File

@ -8,15 +8,12 @@ package main
*/ */
import "C" import "C"
import ( import (
"bytes"
"context" "context"
"math" "math"
"os" "os"
"runtime" "runtime"
"time" "time"
"unsafe" "unsafe"
imageSize "github.com/imgproxy/imgproxy/image_size"
) )
type vipsImage struct { 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) err = C.vips_gifload_go(unsafe.Pointer(&data[0]), C.size_t(len(data)), C.int(pages), &tmp)
case imageTypeSVG: case imageTypeSVG:
err = C.vips_svgload_go(unsafe.Pointer(&data[0]), C.size_t(len(data)), C.double(scale), &tmp) 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: case imageTypeHEIC:
err = C.vips_heifload_go(unsafe.Pointer(&data[0]), C.size_t(len(data)), &tmp) err = C.vips_heifload_go(unsafe.Pointer(&data[0]), C.size_t(len(data)), &tmp)
case imageTypeBMP: case imageTypeBMP:

1
vips.h
View File

@ -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_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_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_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_heifload_go(void *buf, size_t len, VipsImage **out);
int vips_bmpload_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); int vips_tiffload_go(void *buf, size_t len, VipsImage **out);