Skip to content
Permalink
Browse files

Load ICO without imagemagick

  • Loading branch information...
DarthSim committed Oct 3, 2019
1 parent bda7e1e commit a3d894a697b9276ca9797eae998973a18cec56ab
Showing with 45 additions and 30 deletions.
  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
@@ -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
}
@@ -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)
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
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:
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);

0 comments on commit a3d894a

Please sign in to comment.
You can’t perform that action at this time.