mirror of
https://github.com/imgproxy/imgproxy.git
synced 2024-11-24 08:12:38 +02:00
Save ICO without ImageMagick
This commit is contained in:
parent
ce31fb8cdc
commit
494af926df
@ -1,6 +1,8 @@
|
||||
# Changelog
|
||||
|
||||
## [Unreleased]
|
||||
### Fix
|
||||
- Fix ICO saving.
|
||||
|
||||
## [2.14.0] - 2020-07-17
|
||||
### Added
|
||||
|
5
utils.go
5
utils.go
@ -3,6 +3,7 @@ package main
|
||||
import (
|
||||
"math"
|
||||
"strings"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func maxInt(a, b int) int {
|
||||
@ -49,3 +50,7 @@ func trimAfter(s string, sep byte) string {
|
||||
}
|
||||
return s[:i]
|
||||
}
|
||||
|
||||
func ptrToBytes(ptr unsafe.Pointer, size int) []byte {
|
||||
return (*[math.MaxInt32]byte)(ptr)[:int(size):int(size)]
|
||||
}
|
||||
|
14
vips.c
14
vips.c
@ -106,7 +106,7 @@ vips_type_find_save_go(int imgtype) {
|
||||
case (GIF):
|
||||
return vips_type_find("VipsOperation", "magicksave_buffer");
|
||||
case (ICO):
|
||||
return vips_type_find("VipsOperation", "magicksave_buffer");
|
||||
return vips_type_find("VipsOperation", "pngsave_buffer");
|
||||
case (BMP):
|
||||
return vips_type_find("VipsOperation", "magicksave_buffer");
|
||||
case (TIFF):
|
||||
@ -585,16 +585,6 @@ vips_gifsave_go(VipsImage *in, void **buf, size_t *len) {
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
vips_icosave_go(VipsImage *in, void **buf, size_t *len) {
|
||||
#if VIPS_SUPPORT_MAGICK
|
||||
return vips_magicksave_buffer(in, buf, len, "format", "ico", NULL);
|
||||
#else
|
||||
vips_error("vips_icosave_go", "Saving ICO is not supported (libvips 8.7+ reuired)");
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
vips_tiffsave_go(VipsImage *in, void **buf, size_t *len, int quality) {
|
||||
#if VIPS_SUPPORT_TIFF
|
||||
@ -608,7 +598,7 @@ vips_tiffsave_go(VipsImage *in, void **buf, size_t *len, int quality) {
|
||||
int
|
||||
vips_bmpsave_go(VipsImage *in, void **buf, size_t *len) {
|
||||
#if VIPS_SUPPORT_MAGICK
|
||||
return vips_magicksave_buffer(in, buf, len, "format", "bmp", "quality", NULL);
|
||||
return vips_magicksave_buffer(in, buf, len, "format", "bmp", NULL);
|
||||
#else
|
||||
vips_error("vips_bmpsave_go", "Saving BMP is not supported");
|
||||
return 1;
|
||||
|
84
vips.go
84
vips.go
@ -8,9 +8,11 @@ package main
|
||||
*/
|
||||
import "C"
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"os"
|
||||
"runtime"
|
||||
"unsafe"
|
||||
@ -179,6 +181,11 @@ func (img *vipsImage) Load(data []byte, imgtype imageType, shrink int, scale flo
|
||||
}
|
||||
|
||||
func (img *vipsImage) Save(imgtype imageType, quality int, stripMeta bool) ([]byte, context.CancelFunc, error) {
|
||||
if imgtype == imageTypeICO {
|
||||
b, err := img.SaveAsIco()
|
||||
return b, func() {}, err
|
||||
}
|
||||
|
||||
var ptr unsafe.Pointer
|
||||
|
||||
cancel := func() {
|
||||
@ -198,8 +205,6 @@ func (img *vipsImage) Save(imgtype imageType, quality int, stripMeta bool) ([]by
|
||||
err = C.vips_webpsave_go(img.VipsImage, &ptr, &imgsize, C.int(quality), gbool(stripMeta))
|
||||
case imageTypeGIF:
|
||||
err = C.vips_gifsave_go(img.VipsImage, &ptr, &imgsize)
|
||||
case imageTypeICO:
|
||||
err = C.vips_icosave_go(img.VipsImage, &ptr, &imgsize)
|
||||
case imageTypeBMP:
|
||||
err = C.vips_bmpsave_go(img.VipsImage, &ptr, &imgsize)
|
||||
case imageTypeTIFF:
|
||||
@ -210,11 +215,82 @@ func (img *vipsImage) Save(imgtype imageType, quality int, stripMeta bool) ([]by
|
||||
return nil, cancel, vipsError()
|
||||
}
|
||||
|
||||
b := (*[math.MaxInt32]byte)(ptr)[:int(imgsize):int(imgsize)]
|
||||
b := ptrToBytes(ptr, int(imgsize))
|
||||
|
||||
return b, cancel, nil
|
||||
}
|
||||
|
||||
func (img *vipsImage) SaveAsIco() ([]byte, error) {
|
||||
if img.Width() > 256 || img.Height() > 256 {
|
||||
return nil, errors.New("Image dimensions is too big. Max dimension size for ICO is 256")
|
||||
}
|
||||
|
||||
var ptr unsafe.Pointer
|
||||
imgsize := C.size_t(0)
|
||||
|
||||
defer func() {
|
||||
C.g_free_go(&ptr)
|
||||
}()
|
||||
|
||||
if C.vips_pngsave_go(img.VipsImage, &ptr, &imgsize, 0, 0, 256) != 0 {
|
||||
return nil, vipsError()
|
||||
}
|
||||
|
||||
b := ptrToBytes(ptr, int(imgsize))
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
buf.Grow(22 + int(imgsize))
|
||||
|
||||
// ICONDIR header
|
||||
if _, err := buf.Write([]byte{0, 0, 1, 0, 1, 0}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// ICONDIRENTRY
|
||||
if _, err := buf.Write([]byte{
|
||||
byte(img.Width() % 256),
|
||||
byte(img.Height() % 256),
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Number of colors. Not supported in our case
|
||||
if err := buf.WriteByte(0); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Reserved
|
||||
if err := buf.WriteByte(0); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Color planes. Always 1 in our case
|
||||
if _, err := buf.Write([]byte{1, 0}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Bits per pixel
|
||||
if img.HasAlpha() {
|
||||
if _, err := buf.Write([]byte{32, 0}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
if _, err := buf.Write([]byte{24, 0}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
// Image data size
|
||||
if err := binary.Write(buf, binary.LittleEndian, uint32(imgsize)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Image data offset. Always 22 in our case
|
||||
if _, err := buf.Write([]byte{22, 0, 0, 0}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if _, err := buf.Write(b); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
func (img *vipsImage) Clear() {
|
||||
if img.VipsImage != nil {
|
||||
C.clear_image(&img.VipsImage)
|
||||
|
Loading…
Reference in New Issue
Block a user