mirror of
				https://github.com/imgproxy/imgproxy.git
				synced 2025-10-30 23:08:02 +02:00 
			
		
		
		
	Fix transparrency in loaded ICO
This commit is contained in:
		| @@ -1,7 +1,6 @@ | ||||
| package imagemeta | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"encoding/binary" | ||||
| 	"io" | ||||
|  | ||||
| @@ -86,51 +85,3 @@ func init() { | ||||
| 		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 | ||||
| } | ||||
|  | ||||
| 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 | ||||
| 	// immediately followed by a BITMAPINFOHEADER. | ||||
| 	const ( | ||||
| @@ -282,7 +282,6 @@ func (img *Image) loadBmp(data []byte) error { | ||||
| 		} | ||||
| 		return img.decodeBmpRGB(r, width, height, 3, topDown, true) | ||||
| 	case 32: | ||||
| 		noAlpha := true | ||||
| 		if infoLen >= 70 { | ||||
| 			// Alpha mask is empty, so no alpha here | ||||
| 			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)) | ||||
| 	if err != nil { | ||||
| 		// Looks like it's BMP with an incomplete header | ||||
| 		if d, err := imagemeta.FixBmpHeader(internalData); err == nil { | ||||
| 			internalType = imagetype.BMP | ||||
| 			internalData = d | ||||
| 		} else { | ||||
| 		d, err := icoFixBmpHeader(internalData) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} else { | ||||
| 		internalType = meta.Format() | ||||
|  | ||||
| 		return img.loadBmp(d, false) | ||||
| 	} | ||||
|  | ||||
| 	internalType = meta.Format() | ||||
|  | ||||
| 	if internalType == imagetype.ICO || !SupportsLoad(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 | ||||
| } | ||||
|  | ||||
| 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 { | ||||
| 		return img.loadBmp(imgdata.Data) | ||||
| 		return img.loadBmp(imgdata.Data, true) | ||||
| 	} | ||||
|  | ||||
| 	var tmp *C.VipsImage | ||||
|   | ||||
		Reference in New Issue
	
	Block a user