Skip to content

Commit a5a6d7b

Browse files
authored
BMPDecoder の全ビット深度対応と、それにあたっての修正 (#1207)
1 parent 66cd64b commit a5a6d7b

File tree

1 file changed

+191
-46
lines changed

1 file changed

+191
-46
lines changed

Siv3D/src/Siv3D/ImageFormat/BMP/BMPDecoder.cpp

+191-46
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ namespace s3d
5656
}
5757

5858
const Size size(header.biWidth, std::abs(header.biHeight));
59-
59+
6060
ImagePixelFormat pixelFormat = ImagePixelFormat::R8G8B8;
6161

6262
if (header.biBitCount == 32)
@@ -77,7 +77,7 @@ namespace s3d
7777
LOG_SCOPED_TRACE(U"BMPDecoder::decode()");
7878

7979
BMPHeader header;
80-
80+
8181
if (not reader.read(header))
8282
{
8383
LOG_FAIL(U"❌ BMPDecoder::decode(): Failed to read header");
@@ -108,91 +108,236 @@ namespace s3d
108108
return{};
109109
}
110110

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+
111125
Image image(width, height);
112126

113127
LOG_VERBOSE(U"BMPHeader::biBitCount: {}"_fmt(header.biBitCount));
114128

115129
switch (const int32 depth = header.biBitCount)
116130
{
117-
case 8:
131+
case 1:
118132
{
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);
123134
const int32 lineStep = reverse ? -width : width;
124135
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)
127141
{
128-
for (int32 y = 0; y < height; ++y)
142+
if (height - y < 4)
129143
{
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+
}
138150

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;
141153

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)
143159
{
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));
145162

146-
pDst->set(src[2], src[1], src[0]);
163+
pDst++->set(src[2], src[1], src[0]);
147164
}
148165

149-
pDstLine += lineStep;
166+
++tmp;
150167
}
151168

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;
153295
}
154296

155297
break;
156298
}
157299
case 24:
158300
case 32:
159301
{
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;
161303
const int32 depthBytes = depth / 8;
162304
const int32 lineStep = reverse ? -width : width;
163305
Color* pDstLine = image[reverse ? height - 1 : 0];
164306

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)
166311
{
167-
for (int32 y = 0; y < height; ++y)
312+
if (height - y < 4)
168313
{
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+
}
180320

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)];
184323

185-
pSrc += depthBytes;
186-
}
324+
for (Color* pDst = pDstLine; pDst != pDstEnd; ++pDst)
325+
{
326+
pDst->set(pSrc[2], pSrc[1], pSrc[0]);
187327

188-
pDstLine += lineStep;
328+
pSrc += depthBytes;
189329
}
190330

191-
std::free(buffer);
331+
pDstLine += lineStep;
192332
}
193333

194334
break;
195335
}
336+
default:
337+
{
338+
LOG_FAIL(U"❌ BMPDecoder::decode(): BMPHeader::biBitCount is invalid");
339+
return{};
340+
}
196341
}
197342

198343
LOG_VERBOSE(U"Image ({}x{}) decoded"_fmt(

0 commit comments

Comments
 (0)