Skip to content

Commit 8324ffe

Browse files
metmoawesomekling
authored andcommitted
LibGfx/BMPWriter: Add support for V3 & V4 DIB headers
This adds very simple support for storing BMP files with BITMAPV3INFOHEADER and BITMAPV4HEADER. This in turn allows us to store alpha channels which is nice for our .pp file format. For the moment no data regarding colorspace is saved, only the bare minimum to make a valid file. Some small restructuring of the code is made to hopefully make it easier to implement more DIB-headers and support for colorspace/gamma correction in the future.
1 parent 9fe363e commit 8324ffe

File tree

2 files changed

+68
-30
lines changed

2 files changed

+68
-30
lines changed

Userland/Libraries/LibGfx/BMPWriter.cpp

Lines changed: 55 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,6 @@
1010

1111
namespace Gfx {
1212

13-
constexpr int bytes_per_pixel = 3;
14-
15-
#define FILE_HEADER_SIZE 14
16-
#define IMAGE_INFORMATION_SIZE 40
17-
#define PIXEL_DATA_OFFSET FILE_HEADER_SIZE + IMAGE_INFORMATION_SIZE
18-
1913
class OutputStreamer {
2014
public:
2115
OutputStreamer(u8* data)
@@ -49,7 +43,7 @@ class OutputStreamer {
4943
u8* m_data;
5044
};
5145

52-
static ByteBuffer write_pixel_data(const RefPtr<Bitmap> bitmap, int pixel_row_data_size)
46+
static ByteBuffer write_pixel_data(const RefPtr<Bitmap> bitmap, int pixel_row_data_size, int bytes_per_pixel, bool include_alpha_channel)
5347
{
5448
int image_size = pixel_row_data_size * bitmap->height();
5549
auto buffer = ByteBuffer::create_uninitialized(image_size);
@@ -62,6 +56,8 @@ static ByteBuffer write_pixel_data(const RefPtr<Bitmap> bitmap, int pixel_row_da
6256
row[x * bytes_per_pixel + 0] = pixel.blue();
6357
row[x * bytes_per_pixel + 1] = pixel.green();
6458
row[x * bytes_per_pixel + 2] = pixel.red();
59+
if (include_alpha_channel)
60+
row[x * bytes_per_pixel + 3] = pixel.alpha();
6561
}
6662
}
6763

@@ -71,41 +67,74 @@ static ByteBuffer write_pixel_data(const RefPtr<Bitmap> bitmap, int pixel_row_da
7167
static ByteBuffer compress_pixel_data(const ByteBuffer& pixel_data, BMPWriter::Compression compression)
7268
{
7369
switch (compression) {
74-
case BMPWriter::Compression::RGB:
70+
case BMPWriter::Compression::BI_BITFIELDS:
71+
case BMPWriter::Compression::BI_RGB:
7572
return pixel_data;
7673
}
7774

7875
VERIFY_NOT_REACHED();
7976
}
8077

81-
ByteBuffer BMPWriter::dump(const RefPtr<Bitmap> bitmap)
78+
ByteBuffer BMPWriter::dump(const RefPtr<Bitmap> bitmap, DibHeader dib_header)
8279
{
83-
int pixel_row_data_size = (bytes_per_pixel * 8 * bitmap->width() + 31) / 32 * 4;
80+
81+
switch (dib_header) {
82+
case DibHeader::Info:
83+
m_compression = Compression::BI_RGB;
84+
m_bytes_per_pixel = 3;
85+
m_include_alpha_channel = false;
86+
break;
87+
case DibHeader::V3:
88+
case DibHeader::V4:
89+
m_compression = Compression::BI_BITFIELDS;
90+
m_bytes_per_pixel = 4;
91+
m_include_alpha_channel = true;
92+
}
93+
94+
const size_t file_header_size = 14;
95+
size_t pixel_data_offset = file_header_size + (u32)dib_header;
96+
97+
int pixel_row_data_size = (m_bytes_per_pixel * 8 * bitmap->width() + 31) / 32 * 4;
8498
int image_size = pixel_row_data_size * bitmap->height();
85-
auto buffer = ByteBuffer::create_uninitialized(PIXEL_DATA_OFFSET);
99+
auto buffer = ByteBuffer::create_uninitialized(pixel_data_offset);
86100

87-
auto pixel_data = write_pixel_data(bitmap, pixel_row_data_size);
101+
auto pixel_data = write_pixel_data(bitmap, pixel_row_data_size, m_bytes_per_pixel, m_include_alpha_channel);
88102
pixel_data = compress_pixel_data(pixel_data, m_compression);
89103

90-
int file_size = PIXEL_DATA_OFFSET + pixel_data.size();
104+
size_t file_size = pixel_data_offset + pixel_data.size();
91105
OutputStreamer streamer(buffer.data());
92106
streamer.write_u8('B');
93107
streamer.write_u8('M');
94108
streamer.write_u32(file_size);
95109
streamer.write_u32(0);
96-
streamer.write_u32(PIXEL_DATA_OFFSET);
97-
98-
streamer.write_u32(IMAGE_INFORMATION_SIZE); // Header size
99-
streamer.write_i32(bitmap->width()); // ImageWidth
100-
streamer.write_i32(bitmap->height()); // ImageHeight
101-
streamer.write_u16(1); // Planes
102-
streamer.write_u16(bytes_per_pixel * 8); // BitsPerPixel
103-
streamer.write_u32((u32)m_compression); // Compression
104-
streamer.write_u32(image_size); // ImageSize
105-
streamer.write_i32(0); // XpixelsPerMeter
106-
streamer.write_i32(0); // YpixelsPerMeter
107-
streamer.write_u32(0); // TotalColors
108-
streamer.write_u32(0); // ImportantColors
110+
streamer.write_u32(pixel_data_offset);
111+
112+
streamer.write_u32((u32)dib_header); // Header size
113+
streamer.write_i32(bitmap->width()); // ImageWidth
114+
streamer.write_i32(bitmap->height()); // ImageHeight
115+
streamer.write_u16(1); // Planes
116+
streamer.write_u16(m_bytes_per_pixel * 8); // BitsPerPixel
117+
streamer.write_u32((u32)m_compression); // Compression
118+
streamer.write_u32(image_size); // ImageSize
119+
streamer.write_i32(0); // XpixelsPerMeter
120+
streamer.write_i32(0); // YpixelsPerMeter
121+
streamer.write_u32(0); // TotalColors
122+
streamer.write_u32(0); // ImportantColors
123+
124+
if (dib_header == DibHeader::V3 || dib_header == DibHeader::V4) {
125+
streamer.write_u32(0x00ff0000); // Red bitmask
126+
streamer.write_u32(0x0000ff00); // Green bitmask
127+
streamer.write_u32(0x000000ff); // Blue bitmask
128+
streamer.write_u32(0xff000000); // Alpha bitmask
129+
}
130+
131+
if (dib_header == DibHeader::V4) {
132+
streamer.write_u32(0); // Colorspace
133+
134+
for (int i = 0; i < 12; i++) {
135+
streamer.write_u32(0); // Endpoints
136+
}
137+
}
109138

110139
buffer.append(pixel_data.data(), pixel_data.size());
111140
return buffer;

Userland/Libraries/LibGfx/BMPWriter.h

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,25 @@ class BMPWriter {
1616
public:
1717
BMPWriter() = default;
1818

19-
ByteBuffer dump(const RefPtr<Bitmap>);
20-
2119
enum class Compression : u32 {
22-
RGB = 0,
20+
BI_RGB = 0,
21+
BI_BITFIELDS = 3,
22+
};
23+
24+
enum class DibHeader : u32 {
25+
Info = 40,
26+
V3 = 56,
27+
V4 = 108,
2328
};
2429

30+
ByteBuffer dump(const RefPtr<Bitmap>, DibHeader dib_header = DibHeader::V4);
31+
2532
inline void set_compression(Compression compression) { m_compression = compression; }
2633

2734
private:
28-
Compression m_compression { Compression::RGB };
35+
Compression m_compression { Compression::BI_BITFIELDS };
36+
int m_bytes_per_pixel { 4 };
37+
bool m_include_alpha_channel { true };
2938
};
3039

3140
}

0 commit comments

Comments
 (0)