@@ -26,28 +26,35 @@ func readUint32(b []byte) uint32 {
26
26
return uint32 (b [0 ]) | uint32 (b [1 ])<< 8 | uint32 (b [2 ])<< 16 | uint32 (b [3 ])<< 24
27
27
}
28
28
29
- // decodePaletted reads an 8 bit-per-pixel BMP image from r.
29
+ // decodePaletted reads a 1, 2, 4 or 8 bit-per-pixel BMP image from r.
30
30
// If topDown is false, the image rows will be read bottom-up.
31
- func decodePaletted (r io.Reader , c image.Config , topDown bool ) (image.Image , error ) {
31
+ func decodePaletted (r io.Reader , c image.Config , topDown bool , bpp int ) (image.Image , error ) {
32
32
paletted := image .NewPaletted (image .Rect (0 , 0 , c .Width , c .Height ), c .ColorModel .(color.Palette ))
33
33
if c .Width == 0 || c .Height == 0 {
34
34
return paletted , nil
35
35
}
36
- var tmp [4 ]byte
37
36
y0 , y1 , yDelta := c .Height - 1 , - 1 , - 1
38
37
if topDown {
39
38
y0 , y1 , yDelta = 0 , c .Height , + 1
40
39
}
40
+
41
+ pixelsPerByte := 8 / bpp
42
+ // Pad up to ensure each row is 4-bytes aligned.
43
+ bytesPerRow := ((c .Width + pixelsPerByte - 1 )/ pixelsPerByte + 3 ) &^ 3
44
+ b := make ([]byte , bytesPerRow )
45
+
41
46
for y := y0 ; y != y1 ; y += yDelta {
42
47
p := paletted .Pix [y * paletted .Stride : y * paletted .Stride + c .Width ]
43
- if _ , err := io .ReadFull (r , p ); err != nil {
48
+ if _ , err := io .ReadFull (r , b ); err != nil {
44
49
return nil , err
45
50
}
46
- // Each row is 4-byte aligned.
47
- if c .Width % 4 != 0 {
48
- _ , err := io .ReadFull (r , tmp [:4 - c .Width % 4 ])
49
- if err != nil {
50
- return nil , err
51
+ byteIndex , bitIndex , mask := 0 , 8 , byte ((1 << bpp )- 1 )
52
+ for pixIndex := 0 ; pixIndex < c .Width ; pixIndex ++ {
53
+ bitIndex -= bpp
54
+ p [pixIndex ] = (b [byteIndex ]) >> bitIndex & mask
55
+ if bitIndex == 0 {
56
+ byteIndex ++
57
+ bitIndex = 8
51
58
}
52
59
}
53
60
}
@@ -118,8 +125,8 @@ func Decode(r io.Reader) (image.Image, error) {
118
125
return nil , err
119
126
}
120
127
switch bpp {
121
- case 8 :
122
- return decodePaletted (r , c , topDown )
128
+ case 1 , 2 , 4 , 8 :
129
+ return decodePaletted (r , c , topDown , bpp )
123
130
case 24 :
124
131
return decodeRGB (r , c , topDown )
125
132
case 32 :
@@ -190,12 +197,12 @@ func decodeConfig(r io.Reader) (config image.Config, bitsPerPixel int, topDown b
190
197
return image.Config {}, 0 , false , false , ErrUnsupported
191
198
}
192
199
switch bpp {
193
- case 8 :
200
+ case 1 , 2 , 4 , 8 :
194
201
colorUsed := readUint32 (b [46 :50 ])
195
- // If colorUsed is 0, it is set to the maximum number of colors for the given bpp, which is 2^bpp.
202
+
196
203
if colorUsed == 0 {
197
- colorUsed = 256
198
- } else if colorUsed > 256 {
204
+ colorUsed = 1 << bpp
205
+ } else if colorUsed > ( 1 << bpp ) {
199
206
return image.Config {}, 0 , false , false , ErrUnsupported
200
207
}
201
208
@@ -212,7 +219,7 @@ func decodeConfig(r io.Reader) (config image.Config, bitsPerPixel int, topDown b
212
219
// Every 4th byte is padding.
213
220
pcm [i ] = color.RGBA {b [4 * i + 2 ], b [4 * i + 1 ], b [4 * i + 0 ], 0xFF }
214
221
}
215
- return image.Config {ColorModel : pcm , Width : width , Height : height }, 8 , topDown , false , nil
222
+ return image.Config {ColorModel : pcm , Width : width , Height : height }, int ( bpp ) , topDown , false , nil
216
223
case 24 :
217
224
if offset != fileHeaderLen + infoLen {
218
225
return image.Config {}, 0 , false , false , ErrUnsupported
0 commit comments