4 * This file is part of OpenTTD.
5 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
6 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
7 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
10 /** @file bmp.cpp Read and write support for bmps. */
14 #include "core/bitmath_func.hpp"
15 #include "core/alloc_func.hpp"
16 #include "core/mem_func.hpp"
18 #include "safeguards.h"
20 void BmpInitializeBuffer(BmpBuffer
*buffer
, FILE *file
)
25 buffer
->real_pos
= ftell(file
);
28 static inline void AdvanceBuffer(BmpBuffer
*buffer
)
30 if (buffer
->read
< 0) return;
32 buffer
->read
= (int)fread(buffer
->data
, 1, BMP_BUFFER_SIZE
, buffer
->file
);
36 static inline bool EndOfBuffer(BmpBuffer
*buffer
)
38 if (buffer
->read
< 0) return false;
40 if (buffer
->pos
== buffer
->read
|| buffer
->pos
< 0) AdvanceBuffer(buffer
);
41 return buffer
->pos
== buffer
->read
;
44 static inline byte
ReadByte(BmpBuffer
*buffer
)
46 if (buffer
->read
< 0) return 0;
48 if (buffer
->pos
== buffer
->read
|| buffer
->pos
< 0) AdvanceBuffer(buffer
);
50 return buffer
->data
[buffer
->pos
++];
53 static inline uint16
ReadWord(BmpBuffer
*buffer
)
55 uint16 var
= ReadByte(buffer
);
56 return var
| (ReadByte(buffer
) << 8);
59 static inline uint32
ReadDword(BmpBuffer
*buffer
)
61 uint32 var
= ReadWord(buffer
);
62 return var
| (ReadWord(buffer
) << 16);
65 static inline void SkipBytes(BmpBuffer
*buffer
, int bytes
)
68 for (i
= 0; i
< bytes
; i
++) ReadByte(buffer
);
71 static inline void SetStreamOffset(BmpBuffer
*buffer
, int offset
)
73 if (fseek(buffer
->file
, offset
, SEEK_SET
) < 0) {
77 buffer
->real_pos
= offset
;
78 AdvanceBuffer(buffer
);
82 * Reads a 1 bpp uncompressed bitmap
83 * The bitmap is converted to a 8 bpp bitmap
85 static inline bool BmpRead1(BmpBuffer
*buffer
, BmpInfo
*info
, BmpData
*data
)
88 byte pad
= GB(4 - info
->width
/ 8, 0, 2);
91 for (y
= info
->height
; y
> 0; y
--) {
93 pixel_row
= &data
->bitmap
[(y
- 1) * info
->width
];
94 while (x
< info
->width
) {
95 if (EndOfBuffer(buffer
)) return false; // the file is shorter than expected
97 for (i
= 8; i
> 0; i
--) {
98 if (x
< info
->width
) *pixel_row
++ = GB(b
, i
- 1, 1);
102 /* Padding for 32 bit align */
103 SkipBytes(buffer
, pad
);
109 * Reads a 4 bpp uncompressed bitmap
110 * The bitmap is converted to a 8 bpp bitmap
112 static inline bool BmpRead4(BmpBuffer
*buffer
, BmpInfo
*info
, BmpData
*data
)
115 byte pad
= GB(4 - info
->width
/ 2, 0, 2);
118 for (y
= info
->height
; y
> 0; y
--) {
120 pixel_row
= &data
->bitmap
[(y
- 1) * info
->width
];
121 while (x
< info
->width
) {
122 if (EndOfBuffer(buffer
)) return false; // the file is shorter than expected
123 b
= ReadByte(buffer
);
124 *pixel_row
++ = GB(b
, 4, 4);
126 if (x
< info
->width
) {
127 *pixel_row
++ = GB(b
, 0, 4);
131 /* Padding for 32 bit align */
132 SkipBytes(buffer
, pad
);
138 * Reads a 4-bit RLE compressed bitmap
139 * The bitmap is converted to a 8 bpp bitmap
141 static inline bool BmpRead4Rle(BmpBuffer
*buffer
, BmpInfo
*info
, BmpData
*data
)
144 uint y
= info
->height
- 1;
145 byte
*pixel
= &data
->bitmap
[y
* info
->width
];
146 while (y
!= 0 || x
< info
->width
) {
147 if (EndOfBuffer(buffer
)) return false; // the file is shorter than expected
149 byte n
= ReadByte(buffer
);
150 byte c
= ReadByte(buffer
);
153 case 0: // end of line
155 if (y
== 0) return false;
156 pixel
= &data
->bitmap
[--y
* info
->width
];
159 case 1: // end of bitmap
163 if (EndOfBuffer(buffer
)) return false;
164 byte dx
= ReadByte(buffer
);
165 byte dy
= ReadByte(buffer
);
167 /* Check for over- and underflow. */
168 if (x
+ dx
>= info
->width
|| x
+ dx
< x
|| dy
> y
) return false;
172 pixel
= &data
->bitmap
[y
* info
->width
+ x
];
176 default: { // uncompressed
179 if (EndOfBuffer(buffer
) || x
>= info
->width
) return false;
180 byte b
= ReadByte(buffer
);
181 *pixel
++ = GB(b
, 4, 4);
184 if (x
>= info
->width
) return false;
185 *pixel
++ = GB(b
, 0, 4);
189 /* Padding for 16 bit align */
190 SkipBytes(buffer
, ((c
+ 1) / 2) % 2);
195 /* Apparently it is common to encounter BMPs where the count of
196 * pixels to be written is higher than the remaining line width.
197 * Ignore the superfluous pixels instead of reporting an error. */
199 while (x
< info
->width
&& i
++ < n
) {
200 *pixel
++ = GB(c
, 4, 4);
202 if (x
< info
->width
&& i
++ < n
) {
203 *pixel
++ = GB(c
, 0, 4);
213 * Reads a 8 bpp bitmap
215 static inline bool BmpRead8(BmpBuffer
*buffer
, BmpInfo
*info
, BmpData
*data
)
219 byte pad
= GB(4 - info
->width
, 0, 2);
221 for (y
= info
->height
; y
> 0; y
--) {
222 if (EndOfBuffer(buffer
)) return false; // the file is shorter than expected
223 pixel
= &data
->bitmap
[(y
- 1) * info
->width
];
224 for (i
= 0; i
< info
->width
; i
++) *pixel
++ = ReadByte(buffer
);
225 /* Padding for 32 bit align */
226 SkipBytes(buffer
, pad
);
232 * Reads a 8-bit RLE compressed bpp bitmap
234 static inline bool BmpRead8Rle(BmpBuffer
*buffer
, BmpInfo
*info
, BmpData
*data
)
237 uint y
= info
->height
- 1;
238 byte
*pixel
= &data
->bitmap
[y
* info
->width
];
239 while (y
!= 0 || x
< info
->width
) {
240 if (EndOfBuffer(buffer
)) return false; // the file is shorter than expected
242 byte n
= ReadByte(buffer
);
243 byte c
= ReadByte(buffer
);
246 case 0: // end of line
248 if (y
== 0) return false;
249 pixel
= &data
->bitmap
[--y
* info
->width
];
252 case 1: // end of bitmap
256 if (EndOfBuffer(buffer
)) return false;
257 byte dx
= ReadByte(buffer
);
258 byte dy
= ReadByte(buffer
);
260 /* Check for over- and underflow. */
261 if (x
+ dx
>= info
->width
|| x
+ dx
< x
|| dy
> y
) return false;
265 pixel
= &data
->bitmap
[y
* info
->width
+ x
];
269 default: { // uncompressed
270 for (uint i
= 0; i
< c
; i
++) {
271 if (EndOfBuffer(buffer
) || x
>= info
->width
) return false;
272 *pixel
++ = ReadByte(buffer
);
275 /* Padding for 16 bit align */
276 SkipBytes(buffer
, c
% 2);
281 /* Apparently it is common to encounter BMPs where the count of
282 * pixels to be written is higher than the remaining line width.
283 * Ignore the superfluous pixels instead of reporting an error. */
284 for (uint i
= 0; x
< info
->width
&& i
< n
; i
++) {
294 * Reads a 24 bpp uncompressed bitmap
296 static inline bool BmpRead24(BmpBuffer
*buffer
, BmpInfo
*info
, BmpData
*data
)
299 byte pad
= GB(4 - info
->width
* 3, 0, 2);
301 for (y
= info
->height
; y
> 0; y
--) {
302 pixel_row
= &data
->bitmap
[(y
- 1) * info
->width
* 3];
303 for (x
= 0; x
< info
->width
; x
++) {
304 if (EndOfBuffer(buffer
)) return false; // the file is shorter than expected
305 *(pixel_row
+ 2) = ReadByte(buffer
); // green
306 *(pixel_row
+ 1) = ReadByte(buffer
); // blue
307 *pixel_row
= ReadByte(buffer
); // red
310 /* Padding for 32 bit align */
311 SkipBytes(buffer
, pad
);
317 * Reads bitmap headers, and palette (if any)
319 bool BmpReadHeader(BmpBuffer
*buffer
, BmpInfo
*info
, BmpData
*data
)
322 assert(info
!= nullptr);
325 /* Reading BMP header */
326 if (ReadWord(buffer
) != 0x4D42) return false; // signature should be 'BM'
327 SkipBytes(buffer
, 8); // skip file size and reserved
328 info
->offset
= ReadDword(buffer
);
330 /* Reading info header */
331 header_size
= ReadDword(buffer
);
332 if (header_size
< 12) return false; // info header should be at least 12 bytes long
334 info
->os2_bmp
= (header_size
== 12); // OS/2 1.x or windows 2.x info header is 12 bytes long
337 info
->width
= ReadWord(buffer
);
338 info
->height
= ReadWord(buffer
);
341 info
->width
= ReadDword(buffer
);
342 info
->height
= ReadDword(buffer
);
346 if (ReadWord(buffer
) != 1) return false; // BMP can have only 1 plane
348 info
->bpp
= ReadWord(buffer
);
349 if (info
->bpp
!= 1 && info
->bpp
!= 4 && info
->bpp
!= 8 && info
->bpp
!= 24) {
350 /* Only 1 bpp, 4 bpp, 8bpp and 24 bpp bitmaps are supported */
354 /* Reads compression method if available in info header*/
355 if ((header_size
-= 4) >= 4) {
356 info
->compression
= ReadDword(buffer
);
360 /* Only 4-bit and 8-bit rle compression is supported */
361 if (info
->compression
> 2 || (info
->compression
> 0 && !(info
->bpp
== 4 || info
->bpp
== 8))) return false;
363 if (info
->bpp
<= 8) {
366 /* Reads number of colours if available in info header */
367 if (header_size
>= 16) {
368 SkipBytes(buffer
, 12); // skip image size and resolution
369 info
->palette_size
= ReadDword(buffer
); // number of colours in palette
370 SkipBytes(buffer
, header_size
- 16); // skip the end of info header
372 if (info
->palette_size
== 0) info
->palette_size
= 1 << info
->bpp
;
374 data
->palette
= CallocT
<Colour
>(info
->palette_size
);
376 for (i
= 0; i
< info
->palette_size
; i
++) {
377 data
->palette
[i
].b
= ReadByte(buffer
);
378 data
->palette
[i
].g
= ReadByte(buffer
);
379 data
->palette
[i
].r
= ReadByte(buffer
);
380 if (!info
->os2_bmp
) SkipBytes(buffer
, 1); // unused
384 return buffer
->real_pos
<= info
->offset
;
389 * 1 bpp and 4 bpp bitmaps are converted to 8 bpp bitmaps
391 bool BmpReadBitmap(BmpBuffer
*buffer
, BmpInfo
*info
, BmpData
*data
)
393 assert(info
!= nullptr && data
!= nullptr);
395 data
->bitmap
= CallocT
<byte
>(info
->width
* info
->height
* ((info
->bpp
== 24) ? 3 : 1));
398 SetStreamOffset(buffer
, info
->offset
);
399 switch (info
->compression
) {
400 case 0: // no compression
402 case 1: return BmpRead1(buffer
, info
, data
);
403 case 4: return BmpRead4(buffer
, info
, data
);
404 case 8: return BmpRead8(buffer
, info
, data
);
405 case 24: return BmpRead24(buffer
, info
, data
);
406 default: NOT_REACHED();
408 case 1: return BmpRead8Rle(buffer
, info
, data
); // 8-bit RLE compression
409 case 2: return BmpRead4Rle(buffer
, info
, data
); // 4-bit RLE compression
410 default: NOT_REACHED();
414 void BmpDestroyData(BmpData
*data
)
416 assert(data
!= nullptr);