image/bmp: support v4 and v5 info header versions
Decode BITMAPV4INFOHEADER and BITMAPV5INFOHEADER in addition to BITMAPINFOHEADER and check if any of their features are used. If this is not the case, the bmp can be decoded as if it had the BITMAPINFOHEADER. Otherwise an ErrUnsupported is returned. The colormap.bmp and yellow_rose-small-v5.bmp files were generated using imagemagick using the following conversions: convert video-001.bmp -depth 8 -palette colormap.bmp convert yellow_rose-small.bmp -format BMP5 yellow_rose-small-v5.bmp The corresponding png files were created using imagemagick convert without any arguments. Fixes golang/go#27767 Change-Id: I5c0138b231c68132d39a29c71b61faa546921511 Reviewed-on: https://go-review.googlesource.com/c/141799 Reviewed-by: Nigel Tao <nigeltao@golang.org> Run-TryBot: Nigel Tao <nigeltao@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org>
This commit is contained in:
parent
991ec62608
commit
a9455cf03d
|
@ -139,18 +139,24 @@ func decodeConfig(r io.Reader) (config image.Config, bitsPerPixel int, topDown b
|
|||
const (
|
||||
fileHeaderLen = 14
|
||||
infoHeaderLen = 40
|
||||
v4InfoHeaderLen = 108
|
||||
v5InfoHeaderLen = 124
|
||||
)
|
||||
var b [1024]byte
|
||||
if _, err := io.ReadFull(r, b[:fileHeaderLen+infoHeaderLen]); err != nil {
|
||||
if _, err := io.ReadFull(r, b[:fileHeaderLen+4]); err != nil {
|
||||
return image.Config{}, 0, false, err
|
||||
}
|
||||
if string(b[:2]) != "BM" {
|
||||
return image.Config{}, 0, false, errors.New("bmp: invalid format")
|
||||
}
|
||||
offset := readUint32(b[10:14])
|
||||
if readUint32(b[14:18]) != infoHeaderLen {
|
||||
infoLen := readUint32(b[14:18])
|
||||
if infoLen != infoHeaderLen && infoLen != v4InfoHeaderLen && infoLen != v5InfoHeaderLen {
|
||||
return image.Config{}, 0, false, ErrUnsupported
|
||||
}
|
||||
if _, err := io.ReadFull(r, b[fileHeaderLen+4:fileHeaderLen+infoLen]); err != nil {
|
||||
return image.Config{}, 0, false, err
|
||||
}
|
||||
width := int(int32(readUint32(b[18:22])))
|
||||
height := int(int32(readUint32(b[22:26])))
|
||||
if height < 0 {
|
||||
|
@ -161,12 +167,19 @@ func decodeConfig(r io.Reader) (config image.Config, bitsPerPixel int, topDown b
|
|||
}
|
||||
// We only support 1 plane, 8 or 24 bits per pixel and no compression.
|
||||
planes, bpp, compression := readUint16(b[26:28]), readUint16(b[28:30]), readUint32(b[30:34])
|
||||
// if compression is set to BITFIELDS, but the bitmask is set to the default bitmask
|
||||
// that would be used if compression was set to 0, we can continue as if compression was 0
|
||||
if compression == 3 && infoLen > infoHeaderLen &&
|
||||
readUint32(b[54:58]) == 0xff0000 && readUint32(b[58:62]) == 0xff00 &&
|
||||
readUint32(b[62:66]) == 0xff && readUint32(b[66:70]) == 0xff000000 {
|
||||
compression = 0
|
||||
}
|
||||
if planes != 1 || compression != 0 {
|
||||
return image.Config{}, 0, false, ErrUnsupported
|
||||
}
|
||||
switch bpp {
|
||||
case 8:
|
||||
if offset != fileHeaderLen+infoHeaderLen+256*4 {
|
||||
if offset != fileHeaderLen+infoLen+256*4 {
|
||||
return image.Config{}, 0, false, ErrUnsupported
|
||||
}
|
||||
_, err = io.ReadFull(r, b[:256*4])
|
||||
|
@ -181,12 +194,12 @@ func decodeConfig(r io.Reader) (config image.Config, bitsPerPixel int, topDown b
|
|||
}
|
||||
return image.Config{ColorModel: pcm, Width: width, Height: height}, 8, topDown, nil
|
||||
case 24:
|
||||
if offset != fileHeaderLen+infoHeaderLen {
|
||||
if offset != fileHeaderLen+infoLen {
|
||||
return image.Config{}, 0, false, ErrUnsupported
|
||||
}
|
||||
return image.Config{ColorModel: color.RGBAModel, Width: width, Height: height}, 24, topDown, nil
|
||||
case 32:
|
||||
if offset != fileHeaderLen+infoHeaderLen {
|
||||
if offset != fileHeaderLen+infoLen {
|
||||
return image.Config{}, 0, false, ErrUnsupported
|
||||
}
|
||||
return image.Config{ColorModel: color.RGBAModel, Width: width, Height: height}, 32, topDown, nil
|
||||
|
|
|
@ -38,8 +38,10 @@ func compare(img0, img1 image.Image) error {
|
|||
// same pixel data.
|
||||
func TestDecode(t *testing.T) {
|
||||
testCases := []string{
|
||||
"colormap",
|
||||
"video-001",
|
||||
"yellow_rose-small",
|
||||
"yellow_rose-small-v5",
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
|
|
BIN
testdata/colormap.bmp
vendored
Normal file
BIN
testdata/colormap.bmp
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 16 KiB |
BIN
testdata/colormap.png
vendored
Normal file
BIN
testdata/colormap.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 27 KiB |
BIN
testdata/yellow_rose-small-v5.bmp
vendored
Normal file
BIN
testdata/yellow_rose-small-v5.bmp
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 906 B |
BIN
testdata/yellow_rose-small-v5.png
vendored
Normal file
BIN
testdata/yellow_rose-small-v5.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 939 B |
Loading…
Reference in New Issue
Block a user