@@ -56,7 +56,7 @@ namespace s3d
56
56
}
57
57
58
58
const Size size (header.biWidth , std::abs (header.biHeight ));
59
-
59
+
60
60
ImagePixelFormat pixelFormat = ImagePixelFormat::R8G8B8;
61
61
62
62
if (header.biBitCount == 32 )
@@ -77,7 +77,7 @@ namespace s3d
77
77
LOG_SCOPED_TRACE (U" BMPDecoder::decode()" );
78
78
79
79
BMPHeader header;
80
-
80
+
81
81
if (not reader.read (header))
82
82
{
83
83
LOG_FAIL (U" ❌ BMPDecoder::decode(): Failed to read header" );
@@ -108,91 +108,236 @@ namespace s3d
108
108
return {};
109
109
}
110
110
111
+ const uint32 paletteSize = ((header.biBitCount > 8 ) ? 0 : (header.biClrUsed == 0 ) ? (1 << header.biBitCount ) : header.biClrUsed );
112
+ Array<uint8> paletteOwner (paletteSize * 4 );
113
+ const auto palette = paletteOwner.data ();
114
+
115
+ if (paletteSize)
116
+ {
117
+ reader.read (palette, paletteOwner.size ());
118
+ }
119
+
120
+ if (header.bfOffBits > (sizeof (header) + paletteOwner.size ()))
121
+ {
122
+ reader.setPos (header.bfOffBits );
123
+ }
124
+
111
125
Image image (width, height);
112
126
113
127
LOG_VERBOSE (U" BMPHeader::biBitCount: {}" _fmt (header.biBitCount ));
114
128
115
129
switch (const int32 depth = header.biBitCount )
116
130
{
117
- case 8 :
131
+ case 1 :
118
132
{
119
- uint8 palette[1024 ];
120
- reader.read (palette);
121
-
122
- const uint32 rowSize = width + (width % 4 ? 4 - width % 4 : 0 );
133
+ const uint32 rowSize = ((width + 31 ) / 32 * 4 );
123
134
const int32 lineStep = reverse ? -width : width;
124
135
Color* pDstLine = image[reverse ? height - 1 : 0 ];
125
-
126
- if (uint8* const buffer = static_cast <uint8*>(std::malloc (rowSize * 4 )))
136
+
137
+ Array<uint8> bufferOwner (rowSize * 4 );
138
+ const auto buffer = bufferOwner.data ();
139
+
140
+ for (int32 y = 0 ; y < height; ++y)
127
141
{
128
- for (int32 y = 0 ; y < height; ++y )
142
+ if (height - y < 4 )
129
143
{
130
- if (height - y < 4 )
131
- {
132
- reader.read (buffer, rowSize * (height - y));
133
- }
134
- else if (y % 4 == 0 )
135
- {
136
- reader.read (buffer, rowSize * 4 );
137
- }
144
+ reader.read (buffer, rowSize * (height - y));
145
+ }
146
+ else if (y % 4 == 0 )
147
+ {
148
+ reader.read (buffer, rowSize * 4 );
149
+ }
138
150
139
- uint8* tmp = &buffer[rowSize * (y % 4 )];
140
- const Color* const pDstEnd = pDstLine + width ;
151
+ uint8* tmp = &buffer[rowSize * (y % 4 )];
152
+ Color* pDst = pDstLine;
141
153
142
- for (Color* pDst = pDstLine; pDst != pDstEnd; ++pDst)
154
+ for (int32 x = 0 ; x < width; x += 8 )
155
+ {
156
+ const int32 n = Min (8 , (width - x));
157
+
158
+ for (int32 i = 0 ; i < n; ++i)
143
159
{
144
- const uint8* src = palette + (static_cast <size_t >(*tmp++) << 2 );
160
+ const size_t index = ((*tmp >> (7 - i)) & 1 );
161
+ const uint8* src = (palette + (index << 2 ));
145
162
146
- pDst->set (src[2 ], src[1 ], src[0 ]);
163
+ pDst++ ->set (src[2 ], src[1 ], src[0 ]);
147
164
}
148
165
149
- pDstLine += lineStep ;
166
+ ++tmp ;
150
167
}
151
168
152
- std::free (buffer);
169
+ pDstLine += lineStep;
170
+ }
171
+
172
+ break ;
173
+ }
174
+ case 4 :
175
+ {
176
+ const uint32 rowSize = ((width + 7 ) / 8 * 4 );
177
+ const int32 lineStep = reverse ? -width : width;
178
+ Color* pDstLine = image[reverse ? height - 1 : 0 ];
179
+
180
+ Array<uint8> bufferOwner (rowSize * 4 );
181
+ const auto buffer = bufferOwner.data ();
182
+
183
+ for (int32 y = 0 ; y < height; ++y)
184
+ {
185
+ if (height - y < 4 )
186
+ {
187
+ reader.read (buffer, rowSize * (height - y));
188
+ }
189
+ else if (y % 4 == 0 )
190
+ {
191
+ reader.read (buffer, rowSize * 4 );
192
+ }
193
+
194
+ uint8* tmp = &buffer[rowSize * (y % 4 )];
195
+ Color* pDst = pDstLine;
196
+ const int32 w = (width - 1 );
197
+
198
+ for (int32 x = 0 ; x < w; x += 2 )
199
+ {
200
+ const size_t index1 = ((*tmp >> 4 ) & 0x0f );
201
+ const size_t index2 = (*tmp & 0x0f );
202
+ const uint8* src1 = (palette + (index1 << 2 ));
203
+ const uint8* src2 = (palette + (index2 << 2 ));
204
+
205
+ pDst++->set (src1[2 ], src1[1 ], src1[0 ]);
206
+ pDst++->set (src2[2 ], src2[1 ], src2[0 ]);
207
+
208
+ ++tmp;
209
+ }
210
+
211
+ if (width & 1 )
212
+ {
213
+ const size_t index = ((*tmp >> 4 ) & 0x0f );
214
+ const uint8* src = (palette + (index << 2 ));
215
+
216
+ pDst++->set (src[2 ], src[1 ], src[0 ]);
217
+ }
218
+
219
+ pDstLine += lineStep;
220
+ }
221
+
222
+ break ;
223
+ }
224
+ case 8 :
225
+ {
226
+ const uint32 rowSize = width + (width % 4 ? 4 - width % 4 : 0 );
227
+ const int32 lineStep = reverse ? -width : width;
228
+ Color* pDstLine = image[reverse ? height - 1 : 0 ];
229
+
230
+ Array<uint8> bufferOwner (rowSize * 4 );
231
+ const auto buffer = bufferOwner.data ();
232
+
233
+ for (int32 y = 0 ; y < height; ++y)
234
+ {
235
+ if (height - y < 4 )
236
+ {
237
+ reader.read (buffer, rowSize * (height - y));
238
+ }
239
+ else if (y % 4 == 0 )
240
+ {
241
+ reader.read (buffer, rowSize * 4 );
242
+ }
243
+
244
+ uint8* tmp = &buffer[rowSize * (y % 4 )];
245
+ const Color* const pDstEnd = pDstLine + width;
246
+
247
+ for (Color* pDst = pDstLine; pDst != pDstEnd; ++pDst)
248
+ {
249
+ const uint8* src = palette + (static_cast <size_t >(*tmp++) << 2 );
250
+
251
+ pDst->set (src[2 ], src[1 ], src[0 ]);
252
+ }
253
+
254
+ pDstLine += lineStep;
255
+ }
256
+
257
+ break ;
258
+ }
259
+ case 16 :
260
+ {
261
+ const size_t rowSize16 = ((width + 1 ) / 2 * 2 );
262
+ const size_t rowSize = (rowSize16 * 2 );
263
+ const int32 lineStep = reverse ? -width : width;
264
+ Color* pDstLine = image[reverse ? height - 1 : 0 ];
265
+
266
+ Array<uint16> bufferOwner (rowSize16 * 4 );
267
+ const auto buffer = bufferOwner.data ();
268
+
269
+ for (int32 y = 0 ; y < height; ++y)
270
+ {
271
+ if (height - y < 4 )
272
+ {
273
+ reader.read (buffer, rowSize * (height - y));
274
+ }
275
+ else if (y % 4 == 0 )
276
+ {
277
+ reader.read (buffer, rowSize * 4 );
278
+ }
279
+
280
+ const Color* const pDstEnd = pDstLine + width;
281
+ uint16* pSrc = &buffer[rowSize16 * (y % 4 )];
282
+
283
+ for (Color* pDst = pDstLine; pDst != pDstEnd; ++pDst)
284
+ {
285
+ uint32 b = ((*pSrc & 0x001f ) << 3 );
286
+ uint32 g = ((*pSrc & 0x07e0 ) >> 2 );
287
+ uint32 r = ((*pSrc & 0xf800 ) >> 7 );
288
+
289
+ pDst->set (r, g, b);
290
+
291
+ ++pSrc;
292
+ }
293
+
294
+ pDstLine += lineStep;
153
295
}
154
296
155
297
break ;
156
298
}
157
299
case 24 :
158
300
case 32 :
159
301
{
160
- const size_t rowSize = depth == 24 ? width * 3 + width % 4 : width * 4 ;
302
+ const size_t rowSize = depth == 24 ? width * 3 + width % 4 : width * 4 ;
161
303
const int32 depthBytes = depth / 8 ;
162
304
const int32 lineStep = reverse ? -width : width;
163
305
Color* pDstLine = image[reverse ? height - 1 : 0 ];
164
306
165
- if (uint8 * const buffer = static_cast <uint8*>(std::malloc (rowSize * 4 )))
307
+ Array<uint8> bufferOwner (rowSize * 4 );
308
+ const auto buffer = bufferOwner.data ();
309
+
310
+ for (int32 y = 0 ; y < height; ++y)
166
311
{
167
- for (int32 y = 0 ; y < height; ++y )
312
+ if (height - y < 4 )
168
313
{
169
- if (height - y < 4 )
170
- {
171
- reader.read (buffer, rowSize * (height - y));
172
- }
173
- else if (y % 4 == 0 )
174
- {
175
- reader.read (buffer, rowSize * 4 );
176
- }
177
-
178
- const Color* const pDstEnd = pDstLine + width;
179
- uint8* pSrc = &buffer[rowSize * (y % 4 )];
314
+ reader.read (buffer, rowSize * (height - y));
315
+ }
316
+ else if (y % 4 == 0 )
317
+ {
318
+ reader.read (buffer, rowSize * 4 );
319
+ }
180
320
181
- for (Color* pDst = pDstLine; pDst != pDstEnd; ++pDst)
182
- {
183
- pDst->set (pSrc[2 ], pSrc[1 ], pSrc[0 ]);
321
+ const Color* const pDstEnd = pDstLine + width;
322
+ uint8* pSrc = &buffer[rowSize * (y % 4 )];
184
323
185
- pSrc += depthBytes;
186
- }
324
+ for (Color* pDst = pDstLine; pDst != pDstEnd; ++pDst)
325
+ {
326
+ pDst->set (pSrc[2 ], pSrc[1 ], pSrc[0 ]);
187
327
188
- pDstLine += lineStep ;
328
+ pSrc += depthBytes ;
189
329
}
190
330
191
- std::free (buffer) ;
331
+ pDstLine += lineStep ;
192
332
}
193
333
194
334
break ;
195
335
}
336
+ default :
337
+ {
338
+ LOG_FAIL (U" ❌ BMPDecoder::decode(): BMPHeader::biBitCount is invalid" );
339
+ return {};
340
+ }
196
341
}
197
342
198
343
LOG_VERBOSE (U" Image ({}x{}) decoded" _fmt (
0 commit comments