mirror of
https://github.com/imgproxy/imgproxy.git
synced 2025-10-10 12:12:40 +02:00
Add AVIF support
This commit is contained in:
@@ -1,6 +1,8 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
### Added
|
||||||
|
- AVIF support.
|
||||||
|
|
||||||
## [2.15.0] - 2020-09-03
|
## [2.15.0] - 2020-09-03
|
||||||
### Added
|
### Added
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
ARG BASE_IMAGE_VERSION="v1.0.4"
|
ARG BASE_IMAGE_VERSION="v1.2.0"
|
||||||
|
|
||||||
FROM darthsim/imgproxy-base:${BASE_IMAGE_VERSION}
|
FROM darthsim/imgproxy-base:${BASE_IMAGE_VERSION}
|
||||||
LABEL maintainer="Sergey Alexandrovich <darthsim@gmail.com>"
|
LABEL maintainer="Sergey Alexandrovich <darthsim@gmail.com>"
|
||||||
|
@@ -24,6 +24,7 @@ const (
|
|||||||
imageTypeICO = imageType(C.ICO)
|
imageTypeICO = imageType(C.ICO)
|
||||||
imageTypeSVG = imageType(C.SVG)
|
imageTypeSVG = imageType(C.SVG)
|
||||||
imageTypeHEIC = imageType(C.HEIC)
|
imageTypeHEIC = imageType(C.HEIC)
|
||||||
|
imageTypeAVIF = imageType(C.AVIF)
|
||||||
imageTypeBMP = imageType(C.BMP)
|
imageTypeBMP = imageType(C.BMP)
|
||||||
imageTypeTIFF = imageType(C.TIFF)
|
imageTypeTIFF = imageType(C.TIFF)
|
||||||
|
|
||||||
@@ -40,6 +41,7 @@ var (
|
|||||||
"ico": imageTypeICO,
|
"ico": imageTypeICO,
|
||||||
"svg": imageTypeSVG,
|
"svg": imageTypeSVG,
|
||||||
"heic": imageTypeHEIC,
|
"heic": imageTypeHEIC,
|
||||||
|
"avif": imageTypeAVIF,
|
||||||
"bmp": imageTypeBMP,
|
"bmp": imageTypeBMP,
|
||||||
"tiff": imageTypeTIFF,
|
"tiff": imageTypeTIFF,
|
||||||
}
|
}
|
||||||
@@ -52,6 +54,7 @@ var (
|
|||||||
imageTypeICO: "image/x-icon",
|
imageTypeICO: "image/x-icon",
|
||||||
imageTypeSVG: "image/svg+xml",
|
imageTypeSVG: "image/svg+xml",
|
||||||
imageTypeHEIC: "image/heif",
|
imageTypeHEIC: "image/heif",
|
||||||
|
imageTypeAVIF: "image/avif",
|
||||||
imageTypeBMP: "image/bmp",
|
imageTypeBMP: "image/bmp",
|
||||||
imageTypeTIFF: "image/tiff",
|
imageTypeTIFF: "image/tiff",
|
||||||
}
|
}
|
||||||
@@ -64,6 +67,7 @@ var (
|
|||||||
imageTypeICO: "inline; filename=\"%s.ico\"",
|
imageTypeICO: "inline; filename=\"%s.ico\"",
|
||||||
imageTypeSVG: "inline; filename=\"%s.svg\"",
|
imageTypeSVG: "inline; filename=\"%s.svg\"",
|
||||||
imageTypeHEIC: "inline; filename=\"%s.heic\"",
|
imageTypeHEIC: "inline; filename=\"%s.heic\"",
|
||||||
|
imageTypeAVIF: "inline; filename=\"%s.avif\"",
|
||||||
imageTypeBMP: "inline; filename=\"%s.bmp\"",
|
imageTypeBMP: "inline; filename=\"%s.bmp\"",
|
||||||
imageTypeTIFF: "inline; filename=\"%s.tiff\"",
|
imageTypeTIFF: "inline; filename=\"%s.tiff\"",
|
||||||
}
|
}
|
||||||
|
@@ -1,195 +0,0 @@
|
|||||||
package imagemeta
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"encoding/binary"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
)
|
|
||||||
|
|
||||||
const heicBoxHeaderSize = int64(8)
|
|
||||||
|
|
||||||
var heicBrand = []byte("heic")
|
|
||||||
var heicPict = []byte("pict")
|
|
||||||
|
|
||||||
type heicDimensionsData struct {
|
|
||||||
Width, Height int64
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *heicDimensionsData) IsFilled() bool {
|
|
||||||
return d.Width > 0 && d.Height > 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func heicReadBoxHeader(r io.Reader) (boxType string, boxDataSize int64, err error) {
|
|
||||||
b := make([]byte, heicBoxHeaderSize)
|
|
||||||
_, err = io.ReadFull(r, b)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
boxDataSize = int64(binary.BigEndian.Uint32(b[0:4])) - heicBoxHeaderSize
|
|
||||||
boxType = string(b[4:8])
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func heicReadBoxData(r io.Reader, boxDataSize int64) (b []byte, err error) {
|
|
||||||
b = make([]byte, boxDataSize)
|
|
||||||
_, err = io.ReadFull(r, b)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func heicReadFtyp(r io.Reader, boxDataSize int64) error {
|
|
||||||
if boxDataSize < 8 {
|
|
||||||
return errors.New("Invalid ftyp data")
|
|
||||||
}
|
|
||||||
|
|
||||||
data, err := heicReadBoxData(r, boxDataSize)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if bytes.Equal(data[0:4], heicBrand) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if boxDataSize >= 12 {
|
|
||||||
for i := int64(8); i < boxDataSize; i += 4 {
|
|
||||||
if bytes.Equal(data[i:i+4], heicBrand) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return errors.New("Image is not compatible with heic")
|
|
||||||
}
|
|
||||||
|
|
||||||
func heicReadMeta(d *heicDimensionsData, r io.Reader, boxDataSize int64) error {
|
|
||||||
if boxDataSize < 4 {
|
|
||||||
return errors.New("Invalid meta data")
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err := io.ReadFull(r, make([]byte, 4)); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if boxDataSize > 4 {
|
|
||||||
if err := heicReadBoxes(d, io.LimitReader(r, boxDataSize-4)); err != nil && err != io.EOF {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func heicReadHldr(r io.Reader, boxDataSize int64) error {
|
|
||||||
if boxDataSize < 12 {
|
|
||||||
return errors.New("Invalid hdlr data")
|
|
||||||
}
|
|
||||||
|
|
||||||
data, err := heicReadBoxData(r, boxDataSize)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if !bytes.Equal(data[8:12], heicPict) {
|
|
||||||
return fmt.Errorf("Invalid handler. Expected: pict, actual: %s", data[8:12])
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func heicReadIspe(r io.Reader, boxDataSize int64) (w, h int64, err error) {
|
|
||||||
if boxDataSize < 12 {
|
|
||||||
return 0, 0, errors.New("Invalid ispe data")
|
|
||||||
}
|
|
||||||
|
|
||||||
data, err := heicReadBoxData(r, boxDataSize)
|
|
||||||
if err != nil {
|
|
||||||
return 0, 0, err
|
|
||||||
}
|
|
||||||
|
|
||||||
w = int64(binary.BigEndian.Uint32(data[4:8]))
|
|
||||||
h = int64(binary.BigEndian.Uint32(data[8:12]))
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func heicReadBoxes(d *heicDimensionsData, r io.Reader) error {
|
|
||||||
for {
|
|
||||||
boxType, boxDataSize, err := heicReadBoxHeader(r)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if boxDataSize < 0 {
|
|
||||||
return errors.New("Invalid box data")
|
|
||||||
}
|
|
||||||
|
|
||||||
// log.Printf("Box type: %s; Box data size: %d", boxType, boxDataSize)
|
|
||||||
|
|
||||||
switch boxType {
|
|
||||||
case "ftyp":
|
|
||||||
if err := heicReadFtyp(r, boxDataSize); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
case "meta":
|
|
||||||
if err := heicReadMeta(d, r, boxDataSize); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if !d.IsFilled() {
|
|
||||||
return errors.New("Dimensions data wasn't found in meta box")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
case "hdlr":
|
|
||||||
if err := heicReadHldr(r, boxDataSize); err != nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
case "iprp", "ipco":
|
|
||||||
if err := heicReadBoxes(d, io.LimitReader(r, boxDataSize)); err != nil && err != io.EOF {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
case "ispe":
|
|
||||||
w, h, err := heicReadIspe(r, boxDataSize)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if w > d.Width || h > d.Height {
|
|
||||||
d.Width, d.Height = w, h
|
|
||||||
}
|
|
||||||
case "mdat":
|
|
||||||
return errors.New("mdat box occurred before meta box")
|
|
||||||
default:
|
|
||||||
if _, err := heicReadBoxData(r, boxDataSize); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func DecodeHeicMeta(r io.Reader) (Meta, error) {
|
|
||||||
d := new(heicDimensionsData)
|
|
||||||
|
|
||||||
if err := heicReadBoxes(d, r); err != nil && !d.IsFilled() {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &meta{
|
|
||||||
format: "heic",
|
|
||||||
width: int(d.Width),
|
|
||||||
height: int(d.Height),
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
RegisterFormat("????ftypheic", DecodeHeicMeta)
|
|
||||||
RegisterFormat("????ftypheix", DecodeHeicMeta)
|
|
||||||
RegisterFormat("????ftyphevc", DecodeHeicMeta)
|
|
||||||
RegisterFormat("????ftypheim", DecodeHeicMeta)
|
|
||||||
RegisterFormat("????ftypheis", DecodeHeicMeta)
|
|
||||||
RegisterFormat("????ftyphevm", DecodeHeicMeta)
|
|
||||||
RegisterFormat("????ftyphevs", DecodeHeicMeta)
|
|
||||||
RegisterFormat("????ftypmif1", DecodeHeicMeta)
|
|
||||||
}
|
|
212
imagemeta/heif.go
Normal file
212
imagemeta/heif.go
Normal file
@@ -0,0 +1,212 @@
|
|||||||
|
package imagemeta
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/binary"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
const heifBoxHeaderSize = int64(8)
|
||||||
|
|
||||||
|
var heicBrand = []byte("heic")
|
||||||
|
var avifBrand = []byte("avif")
|
||||||
|
var heifPict = []byte("pict")
|
||||||
|
|
||||||
|
type heifData struct {
|
||||||
|
Format string
|
||||||
|
Width, Height int64
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *heifData) IsFilled() bool {
|
||||||
|
return len(d.Format) > 0 && d.Width > 0 && d.Height > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func heifReadBoxHeader(r io.Reader) (boxType string, boxDataSize int64, err error) {
|
||||||
|
b := make([]byte, heifBoxHeaderSize)
|
||||||
|
_, err = io.ReadFull(r, b)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
boxDataSize = int64(binary.BigEndian.Uint32(b[0:4])) - heifBoxHeaderSize
|
||||||
|
boxType = string(b[4:8])
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func heifReadBoxData(r io.Reader, boxDataSize int64) (b []byte, err error) {
|
||||||
|
b = make([]byte, boxDataSize)
|
||||||
|
_, err = io.ReadFull(r, b)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func heifAssignFormat(d *heifData, brand []byte) bool {
|
||||||
|
if bytes.Equal(brand, heicBrand) {
|
||||||
|
d.Format = "heic"
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if bytes.Equal(brand, avifBrand) {
|
||||||
|
d.Format = "avif"
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func heifReadFtyp(d *heifData, r io.Reader, boxDataSize int64) error {
|
||||||
|
if boxDataSize < 8 {
|
||||||
|
return errors.New("Invalid ftyp data")
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := heifReadBoxData(r, boxDataSize)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if heifAssignFormat(d, data[0:4]) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if boxDataSize >= 12 {
|
||||||
|
for i := int64(8); i < boxDataSize; i += 4 {
|
||||||
|
if heifAssignFormat(d, data[i:i+4]) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return errors.New("Image is not compatible with heic/avif")
|
||||||
|
}
|
||||||
|
|
||||||
|
func heifReadMeta(d *heifData, r io.Reader, boxDataSize int64) error {
|
||||||
|
if boxDataSize < 4 {
|
||||||
|
return errors.New("Invalid meta data")
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := io.ReadFull(r, make([]byte, 4)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if boxDataSize > 4 {
|
||||||
|
if err := heifReadBoxes(d, io.LimitReader(r, boxDataSize-4)); err != nil && err != io.EOF {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func heifReadHldr(r io.Reader, boxDataSize int64) error {
|
||||||
|
if boxDataSize < 12 {
|
||||||
|
return errors.New("Invalid hdlr data")
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := heifReadBoxData(r, boxDataSize)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !bytes.Equal(data[8:12], heifPict) {
|
||||||
|
return fmt.Errorf("Invalid handler. Expected: pict, actual: %s", data[8:12])
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func heifReadIspe(r io.Reader, boxDataSize int64) (w, h int64, err error) {
|
||||||
|
if boxDataSize < 12 {
|
||||||
|
return 0, 0, errors.New("Invalid ispe data")
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := heifReadBoxData(r, boxDataSize)
|
||||||
|
if err != nil {
|
||||||
|
return 0, 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
w = int64(binary.BigEndian.Uint32(data[4:8]))
|
||||||
|
h = int64(binary.BigEndian.Uint32(data[8:12]))
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func heifReadBoxes(d *heifData, r io.Reader) error {
|
||||||
|
for {
|
||||||
|
boxType, boxDataSize, err := heifReadBoxHeader(r)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if boxDataSize < 0 {
|
||||||
|
return errors.New("Invalid box data")
|
||||||
|
}
|
||||||
|
|
||||||
|
// log.Printf("Box type: %s; Box data size: %d", boxType, boxDataSize)
|
||||||
|
|
||||||
|
switch boxType {
|
||||||
|
case "ftyp":
|
||||||
|
if err := heifReadFtyp(d, r, boxDataSize); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
case "meta":
|
||||||
|
if err := heifReadMeta(d, r, boxDataSize); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !d.IsFilled() {
|
||||||
|
return errors.New("Dimensions data wasn't found in meta box")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
case "hdlr":
|
||||||
|
if err := heifReadHldr(r, boxDataSize); err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
case "iprp", "ipco":
|
||||||
|
if err := heifReadBoxes(d, io.LimitReader(r, boxDataSize)); err != nil && err != io.EOF {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
case "ispe":
|
||||||
|
w, h, err := heifReadIspe(r, boxDataSize)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if w > d.Width || h > d.Height {
|
||||||
|
d.Width, d.Height = w, h
|
||||||
|
}
|
||||||
|
case "mdat":
|
||||||
|
return errors.New("mdat box occurred before meta box")
|
||||||
|
default:
|
||||||
|
if _, err := heifReadBoxData(r, boxDataSize); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func DecodeHeifMeta(r io.Reader) (Meta, error) {
|
||||||
|
d := new(heifData)
|
||||||
|
|
||||||
|
if err := heifReadBoxes(d, r); err != nil && !d.IsFilled() {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &meta{
|
||||||
|
format: d.Format,
|
||||||
|
width: int(d.Width),
|
||||||
|
height: int(d.Height),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
RegisterFormat("????ftypheic", DecodeHeifMeta)
|
||||||
|
RegisterFormat("????ftypheix", DecodeHeifMeta)
|
||||||
|
RegisterFormat("????ftyphevc", DecodeHeifMeta)
|
||||||
|
RegisterFormat("????ftypheim", DecodeHeifMeta)
|
||||||
|
RegisterFormat("????ftypheis", DecodeHeifMeta)
|
||||||
|
RegisterFormat("????ftyphevm", DecodeHeifMeta)
|
||||||
|
RegisterFormat("????ftyphevs", DecodeHeifMeta)
|
||||||
|
RegisterFormat("????ftypmif1", DecodeHeifMeta)
|
||||||
|
RegisterFormat("????ftypavif", DecodeHeifMeta)
|
||||||
|
}
|
@@ -138,7 +138,7 @@ func canScaleOnLoad(imgtype imageType, scale float64) bool {
|
|||||||
|
|
||||||
func canFitToBytes(imgtype imageType) bool {
|
func canFitToBytes(imgtype imageType) bool {
|
||||||
switch imgtype {
|
switch imgtype {
|
||||||
case imageTypeJPEG, imageTypeWEBP, imageTypeHEIC, imageTypeTIFF:
|
case imageTypeJPEG, imageTypeWEBP, imageTypeAVIF, imageTypeTIFF:
|
||||||
return true
|
return true
|
||||||
default:
|
default:
|
||||||
return false
|
return false
|
||||||
|
14
vips.c
14
vips.c
@@ -85,6 +85,8 @@ vips_type_find_load_go(int imgtype) {
|
|||||||
return vips_type_find("VipsOperation", "svgload_buffer");
|
return vips_type_find("VipsOperation", "svgload_buffer");
|
||||||
case (HEIC):
|
case (HEIC):
|
||||||
return vips_type_find("VipsOperation", "heifload_buffer");
|
return vips_type_find("VipsOperation", "heifload_buffer");
|
||||||
|
case (AVIF):
|
||||||
|
return vips_type_find("VipsOperation", "heifload_buffer");
|
||||||
case (BMP):
|
case (BMP):
|
||||||
return vips_type_find("VipsOperation", "magickload_buffer");
|
return vips_type_find("VipsOperation", "magickload_buffer");
|
||||||
case (TIFF):
|
case (TIFF):
|
||||||
@@ -105,6 +107,8 @@ vips_type_find_save_go(int imgtype) {
|
|||||||
return vips_type_find("VipsOperation", "webpsave_buffer");
|
return vips_type_find("VipsOperation", "webpsave_buffer");
|
||||||
case (GIF):
|
case (GIF):
|
||||||
return vips_type_find("VipsOperation", "magicksave_buffer");
|
return vips_type_find("VipsOperation", "magicksave_buffer");
|
||||||
|
case (AVIF):
|
||||||
|
return vips_type_find("VipsOperation", "heifsave_buffer");
|
||||||
case (ICO):
|
case (ICO):
|
||||||
return vips_type_find("VipsOperation", "pngsave_buffer");
|
return vips_type_find("VipsOperation", "pngsave_buffer");
|
||||||
case (BMP):
|
case (BMP):
|
||||||
@@ -600,6 +604,16 @@ vips_tiffsave_go(VipsImage *in, void **buf, size_t *len, int quality) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
vips_avifsave_go(VipsImage *in, void **buf, size_t *len, int quality) {
|
||||||
|
#if VIPS_SUPPORT_HEIF
|
||||||
|
return vips_heifsave_buffer(in, buf, len, "Q", quality, "compression", VIPS_FOREIGN_HEIF_COMPRESSION_AV1, NULL);
|
||||||
|
#else
|
||||||
|
vips_error("vips_avifsave_go", "Saving AVIF is not supported (libvips 8.6+ reuired)");
|
||||||
|
return 1;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
vips_bmpsave_go(VipsImage *in, void **buf, size_t *len) {
|
vips_bmpsave_go(VipsImage *in, void **buf, size_t *len) {
|
||||||
#if VIPS_SUPPORT_MAGICK
|
#if VIPS_SUPPORT_MAGICK
|
||||||
|
4
vips.go
4
vips.go
@@ -164,7 +164,7 @@ 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 imageTypeHEIC:
|
case imageTypeHEIC, imageTypeAVIF:
|
||||||
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:
|
||||||
err = C.vips_bmpload_go(unsafe.Pointer(&data[0]), C.size_t(len(data)), &tmp)
|
err = C.vips_bmpload_go(unsafe.Pointer(&data[0]), C.size_t(len(data)), &tmp)
|
||||||
@@ -205,6 +205,8 @@ 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))
|
err = C.vips_webpsave_go(img.VipsImage, &ptr, &imgsize, C.int(quality), gbool(stripMeta))
|
||||||
case imageTypeGIF:
|
case imageTypeGIF:
|
||||||
err = C.vips_gifsave_go(img.VipsImage, &ptr, &imgsize)
|
err = C.vips_gifsave_go(img.VipsImage, &ptr, &imgsize)
|
||||||
|
case imageTypeAVIF:
|
||||||
|
err = C.vips_avifsave_go(img.VipsImage, &ptr, &imgsize, C.int(quality))
|
||||||
case imageTypeBMP:
|
case imageTypeBMP:
|
||||||
err = C.vips_bmpsave_go(img.VipsImage, &ptr, &imgsize)
|
err = C.vips_bmpsave_go(img.VipsImage, &ptr, &imgsize)
|
||||||
case imageTypeTIFF:
|
case imageTypeTIFF:
|
||||||
|
3
vips.h
3
vips.h
@@ -13,6 +13,7 @@ enum ImgproxyImageTypes {
|
|||||||
ICO,
|
ICO,
|
||||||
SVG,
|
SVG,
|
||||||
HEIC,
|
HEIC,
|
||||||
|
AVIF,
|
||||||
BMP,
|
BMP,
|
||||||
TIFF
|
TIFF
|
||||||
};
|
};
|
||||||
@@ -90,7 +91,7 @@ int vips_jpegsave_go(VipsImage *in, void **buf, size_t *len, int quality, int in
|
|||||||
int vips_pngsave_go(VipsImage *in, void **buf, size_t *len, int interlace, int quantize, int colors);
|
int vips_pngsave_go(VipsImage *in, void **buf, size_t *len, int interlace, int quantize, int colors);
|
||||||
int vips_webpsave_go(VipsImage *in, void **buf, size_t *len, int quality, gboolean strip);
|
int vips_webpsave_go(VipsImage *in, void **buf, size_t *len, int quality, gboolean strip);
|
||||||
int vips_gifsave_go(VipsImage *in, void **buf, size_t *len);
|
int vips_gifsave_go(VipsImage *in, void **buf, size_t *len);
|
||||||
int vips_icosave_go(VipsImage *in, void **buf, size_t *len);
|
int vips_avifsave_go(VipsImage *in, void **buf, size_t *len, int quality);
|
||||||
int vips_bmpsave_go(VipsImage *in, void **buf, size_t *len);
|
int vips_bmpsave_go(VipsImage *in, void **buf, size_t *len);
|
||||||
int vips_tiffsave_go(VipsImage *in, void **buf, size_t *len, int quality);
|
int vips_tiffsave_go(VipsImage *in, void **buf, size_t *len, int quality);
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user