Browse Source

Fix BMP with <8 BPP

DarthSim 3 years ago
parent
commit
1ab981ef11
2 changed files with 18 additions and 6 deletions
  1. 1 0
      CHANGELOG.md
  2. 17 6
      vips/bmp.go

+ 1 - 0
CHANGELOG.md

@@ -3,6 +3,7 @@
 ## [Unreleased]
 ## [Unreleased]
 ### Added
 ### Added
 - (pro) Add `video_meta` to the `/info` response.
 - (pro) Add `video_meta` to the `/info` response.
+- Add 1/2/4-bit BMP support.
 
 
 ### Fix
 ### Fix
 - Fix Datadog support.
 - Fix Datadog support.

+ 17 - 6
vips/bmp.go

@@ -62,7 +62,7 @@ func prepareBmpCanvas(width, height, bands int) (*C.VipsImage, []byte, error) {
 
 
 // decodeBmpPaletted reads an 8 bit-per-pixel BMP image from r.
 // decodeBmpPaletted reads an 8 bit-per-pixel BMP image from r.
 // If topDown is false, the image rows will be read bottom-up.
 // If topDown is false, the image rows will be read bottom-up.
-func (img *Image) decodeBmpPaletted(r io.Reader, width, height int, palette []Color, topDown bool) error {
+func (img *Image) decodeBmpPaletted(r io.Reader, width, height, bpp int, palette []Color, topDown bool) error {
 	tmp, imgData, err := prepareBmpCanvas(width, height, 3)
 	tmp, imgData, err := prepareBmpCanvas(width, height, 3)
 	if err != nil {
 	if err != nil {
 		return err
 		return err
@@ -76,7 +76,8 @@ func (img *Image) decodeBmpPaletted(r io.Reader, width, height int, palette []Co
 	}()
 	}()
 
 
 	// Each row is 4-byte aligned.
 	// Each row is 4-byte aligned.
-	b := make([]byte, (width+3)&^3)
+	cap := 8 / bpp
+	b := make([]byte, ((width+cap-1)/cap+3)&^3)
 
 
 	y0, y1, yDelta := height-1, -1, -1
 	y0, y1, yDelta := height-1, -1, -1
 	if topDown {
 	if topDown {
@@ -93,8 +94,18 @@ func (img *Image) decodeBmpPaletted(r io.Reader, width, height int, palette []Co
 
 
 		p := imgData[y*stride : (y+1)*stride]
 		p := imgData[y*stride : (y+1)*stride]
 
 
-		for i, j := 0, 0; i < len(p); i, j = i+3, j+1 {
-			c := palette[b[j]]
+		j, bit := 0, 8-bpp
+		for i := 0; i < len(p); i += 3 {
+			pind := (b[j] >> bit) & (1<<bpp - 1)
+
+			if bit == 0 {
+				bit = 8 - bpp
+				j++
+			} else {
+				bit -= bpp
+			}
+
+			c := palette[pind]
 
 
 			p[i+0] = c.R
 			p[i+0] = c.R
 			p[i+1] = c.G
 			p[i+1] = c.G
@@ -245,7 +256,7 @@ func (img *Image) loadBmp(data []byte) error {
 	}
 	}
 
 
 	switch bpp {
 	switch bpp {
-	case 8:
+	case 1, 2, 4, 8:
 		palColors := readUint32(b[46:50])
 		palColors := readUint32(b[46:50])
 
 
 		if offset != fileHeaderLen+infoLen+palColors*4 {
 		if offset != fileHeaderLen+infoLen+palColors*4 {
@@ -264,7 +275,7 @@ func (img *Image) loadBmp(data []byte) error {
 			palette[i] = Color{b[4*i+2], b[4*i+1], b[4*i+0]}
 			palette[i] = Color{b[4*i+2], b[4*i+1], b[4*i+0]}
 		}
 		}
 
 
-		return img.decodeBmpPaletted(r, width, height, palette, topDown)
+		return img.decodeBmpPaletted(r, width, height, int(bpp), palette, topDown)
 	case 24:
 	case 24:
 		if offset != fileHeaderLen+infoLen {
 		if offset != fileHeaderLen+infoLen {
 			return errBmpUnsupported
 			return errBmpUnsupported