1
0
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:
DarthSim
2022-03-14 18:29:40 +06:00
parent e9e5b9e60d
commit 175cb8c41b
4 changed files with 55 additions and 58 deletions

View File

@ -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
}

View File

@ -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

View File

@ -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
}

View File

@ -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