mirror of
https://github.com/imgproxy/imgproxy.git
synced 2025-06-17 22:37:33 +02:00
Fix transparrency in loaded ICO
This commit is contained in:
@ -1,7 +1,6 @@
|
|||||||
package imagemeta
|
package imagemeta
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
@ -86,51 +85,3 @@ func init() {
|
|||||||
func(r io.Reader) (Meta, error) { return DecodeIcoMeta(r) },
|
func(r io.Reader) (Meta, error) { return DecodeIcoMeta(r) },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FixBmpHeader fixes an incomplete header of BMP stored in ICO
|
|
||||||
func FixBmpHeader(b []byte) ([]byte, error) {
|
|
||||||
buf := new(bytes.Buffer)
|
|
||||||
|
|
||||||
fileSize := uint32(14 + len(b))
|
|
||||||
|
|
||||||
buf.Grow(int(fileSize))
|
|
||||||
|
|
||||||
buf.Write(bmpMagick)
|
|
||||||
|
|
||||||
if err := binary.Write(buf, binary.LittleEndian, &fileSize); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
reserved := uint32(0)
|
|
||||||
if err := binary.Write(buf, binary.LittleEndian, &reserved); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
colorUsed := binary.LittleEndian.Uint32(b[32:36])
|
|
||||||
bitCount := binary.LittleEndian.Uint16(b[14:16])
|
|
||||||
|
|
||||||
var pixOffset uint32
|
|
||||||
if colorUsed == 0 && bitCount <= 8 {
|
|
||||||
pixOffset = 14 + 40 + 4*(1<<bitCount)
|
|
||||||
} else {
|
|
||||||
pixOffset = 14 + 40 + 4*colorUsed
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := binary.Write(buf, binary.LittleEndian, &pixOffset); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write size and width
|
|
||||||
buf.Write(b[:8])
|
|
||||||
|
|
||||||
// For some reason ICO stores double height
|
|
||||||
height := binary.LittleEndian.Uint32(b[8:12]) / 2
|
|
||||||
if err := binary.Write(buf, binary.LittleEndian, &height); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write the rest
|
|
||||||
buf.Write(b[12:])
|
|
||||||
|
|
||||||
return buf.Bytes(), nil
|
|
||||||
}
|
|
||||||
|
@ -191,7 +191,7 @@ func (img *Image) decodeBmpRGB(r io.Reader, width, height, bands int, topDown, n
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (img *Image) loadBmp(data []byte) error {
|
func (img *Image) loadBmp(data []byte, noAlpha bool) error {
|
||||||
// We only support those BMP images that are a BITMAPFILEHEADER
|
// We only support those BMP images that are a BITMAPFILEHEADER
|
||||||
// immediately followed by a BITMAPINFOHEADER.
|
// immediately followed by a BITMAPINFOHEADER.
|
||||||
const (
|
const (
|
||||||
@ -282,7 +282,6 @@ func (img *Image) loadBmp(data []byte) error {
|
|||||||
}
|
}
|
||||||
return img.decodeBmpRGB(r, width, height, 3, topDown, true)
|
return img.decodeBmpRGB(r, width, height, 3, topDown, true)
|
||||||
case 32:
|
case 32:
|
||||||
noAlpha := true
|
|
||||||
if infoLen >= 70 {
|
if infoLen >= 70 {
|
||||||
// Alpha mask is empty, so no alpha here
|
// Alpha mask is empty, so no alpha here
|
||||||
noAlpha = readUint32(b[66:70]) == 0
|
noAlpha = readUint32(b[66:70]) == 0
|
||||||
|
59
vips/ico.go
59
vips/ico.go
@ -32,16 +32,16 @@ func (img *Image) loadIco(data []byte, shrink int, scale float64, pages int) err
|
|||||||
meta, err := imagemeta.DecodeMeta(bytes.NewReader(internalData))
|
meta, err := imagemeta.DecodeMeta(bytes.NewReader(internalData))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Looks like it's BMP with an incomplete header
|
// Looks like it's BMP with an incomplete header
|
||||||
if d, err := imagemeta.FixBmpHeader(internalData); err == nil {
|
d, err := icoFixBmpHeader(internalData)
|
||||||
internalType = imagetype.BMP
|
if err != nil {
|
||||||
internalData = d
|
|
||||||
} else {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
internalType = meta.Format()
|
return img.loadBmp(d, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internalType = meta.Format()
|
||||||
|
|
||||||
if internalType == imagetype.ICO || !SupportsLoad(internalType) {
|
if internalType == imagetype.ICO || !SupportsLoad(internalType) {
|
||||||
return fmt.Errorf("Can't load %s from ICO", internalType)
|
return fmt.Errorf("Can't load %s from ICO", internalType)
|
||||||
}
|
}
|
||||||
@ -129,3 +129,50 @@ func (img *Image) saveAsIco() (*imagedata.ImageData, error) {
|
|||||||
|
|
||||||
return &imgdata, nil
|
return &imgdata, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func icoFixBmpHeader(b []byte) ([]byte, error) {
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
|
||||||
|
fileSize := uint32(14 + len(b))
|
||||||
|
|
||||||
|
buf.Grow(int(fileSize))
|
||||||
|
|
||||||
|
buf.WriteString("BM")
|
||||||
|
|
||||||
|
if err := binary.Write(buf, binary.LittleEndian, &fileSize); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
reserved := uint32(0)
|
||||||
|
if err := binary.Write(buf, binary.LittleEndian, &reserved); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
colorUsed := binary.LittleEndian.Uint32(b[32:36])
|
||||||
|
bitCount := binary.LittleEndian.Uint16(b[14:16])
|
||||||
|
|
||||||
|
var pixOffset uint32
|
||||||
|
if colorUsed == 0 && bitCount <= 8 {
|
||||||
|
pixOffset = 14 + 40 + 4*(1<<bitCount)
|
||||||
|
} else {
|
||||||
|
pixOffset = 14 + 40 + 4*colorUsed
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := binary.Write(buf, binary.LittleEndian, &pixOffset); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write size and width
|
||||||
|
buf.Write(b[:8])
|
||||||
|
|
||||||
|
// For some reason ICO stores double height
|
||||||
|
height := binary.LittleEndian.Uint32(b[8:12]) / 2
|
||||||
|
if err := binary.Write(buf, binary.LittleEndian, &height); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write the rest
|
||||||
|
buf.Write(b[12:])
|
||||||
|
|
||||||
|
return buf.Bytes(), nil
|
||||||
|
}
|
||||||
|
@ -208,7 +208,7 @@ func (img *Image) Load(imgdata *imagedata.ImageData, shrink int, scale float64,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if imgdata.Type == imagetype.BMP {
|
if imgdata.Type == imagetype.BMP {
|
||||||
return img.loadBmp(imgdata.Data)
|
return img.loadBmp(imgdata.Data, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
var tmp *C.VipsImage
|
var tmp *C.VipsImage
|
||||||
|
Reference in New Issue
Block a user