summaryrefslogtreecommitdiff
path: root/Userland/Libraries/LibGfx/BMPWriter.cpp
diff options
context:
space:
mode:
authorMarcus Nilsson <brainbomb@gmail.com>2021-07-03 23:50:21 +0200
committerAndreas Kling <kling@serenityos.org>2021-07-05 00:43:00 +0200
commit8324ffefe707c83ce8a952d779d33edcc38d24fe (patch)
tree5da0d1100695060b7dfa58a3382771dafc47217e /Userland/Libraries/LibGfx/BMPWriter.cpp
parent9fe363eaad37915b0071fab369abe527efee4535 (diff)
downloadserenity-8324ffefe707c83ce8a952d779d33edcc38d24fe.zip
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.
Diffstat (limited to 'Userland/Libraries/LibGfx/BMPWriter.cpp')
-rw-r--r--Userland/Libraries/LibGfx/BMPWriter.cpp81
1 files changed, 55 insertions, 26 deletions
diff --git a/Userland/Libraries/LibGfx/BMPWriter.cpp b/Userland/Libraries/LibGfx/BMPWriter.cpp
index 77391a5194..732b2aa9dc 100644
--- a/Userland/Libraries/LibGfx/BMPWriter.cpp
+++ b/Userland/Libraries/LibGfx/BMPWriter.cpp
@@ -10,12 +10,6 @@
namespace Gfx {
-constexpr int bytes_per_pixel = 3;
-
-#define FILE_HEADER_SIZE 14
-#define IMAGE_INFORMATION_SIZE 40
-#define PIXEL_DATA_OFFSET FILE_HEADER_SIZE + IMAGE_INFORMATION_SIZE
-
class OutputStreamer {
public:
OutputStreamer(u8* data)
@@ -49,7 +43,7 @@ private:
u8* m_data;
};
-static ByteBuffer write_pixel_data(const RefPtr<Bitmap> bitmap, int pixel_row_data_size)
+static ByteBuffer write_pixel_data(const RefPtr<Bitmap> bitmap, int pixel_row_data_size, int bytes_per_pixel, bool include_alpha_channel)
{
int image_size = pixel_row_data_size * bitmap->height();
auto buffer = ByteBuffer::create_uninitialized(image_size);
@@ -62,6 +56,8 @@ static ByteBuffer write_pixel_data(const RefPtr<Bitmap> bitmap, int pixel_row_da
row[x * bytes_per_pixel + 0] = pixel.blue();
row[x * bytes_per_pixel + 1] = pixel.green();
row[x * bytes_per_pixel + 2] = pixel.red();
+ if (include_alpha_channel)
+ row[x * bytes_per_pixel + 3] = pixel.alpha();
}
}
@@ -71,41 +67,74 @@ static ByteBuffer write_pixel_data(const RefPtr<Bitmap> bitmap, int pixel_row_da
static ByteBuffer compress_pixel_data(const ByteBuffer& pixel_data, BMPWriter::Compression compression)
{
switch (compression) {
- case BMPWriter::Compression::RGB:
+ case BMPWriter::Compression::BI_BITFIELDS:
+ case BMPWriter::Compression::BI_RGB:
return pixel_data;
}
VERIFY_NOT_REACHED();
}
-ByteBuffer BMPWriter::dump(const RefPtr<Bitmap> bitmap)
+ByteBuffer BMPWriter::dump(const RefPtr<Bitmap> bitmap, DibHeader dib_header)
{
- int pixel_row_data_size = (bytes_per_pixel * 8 * bitmap->width() + 31) / 32 * 4;
+
+ switch (dib_header) {
+ case DibHeader::Info:
+ m_compression = Compression::BI_RGB;
+ m_bytes_per_pixel = 3;
+ m_include_alpha_channel = false;
+ break;
+ case DibHeader::V3:
+ case DibHeader::V4:
+ m_compression = Compression::BI_BITFIELDS;
+ m_bytes_per_pixel = 4;
+ m_include_alpha_channel = true;
+ }
+
+ const size_t file_header_size = 14;
+ size_t pixel_data_offset = file_header_size + (u32)dib_header;
+
+ int pixel_row_data_size = (m_bytes_per_pixel * 8 * bitmap->width() + 31) / 32 * 4;
int image_size = pixel_row_data_size * bitmap->height();
- auto buffer = ByteBuffer::create_uninitialized(PIXEL_DATA_OFFSET);
+ auto buffer = ByteBuffer::create_uninitialized(pixel_data_offset);
- auto pixel_data = write_pixel_data(bitmap, pixel_row_data_size);
+ auto pixel_data = write_pixel_data(bitmap, pixel_row_data_size, m_bytes_per_pixel, m_include_alpha_channel);
pixel_data = compress_pixel_data(pixel_data, m_compression);
- int file_size = PIXEL_DATA_OFFSET + pixel_data.size();
+ size_t file_size = pixel_data_offset + pixel_data.size();
OutputStreamer streamer(buffer.data());
streamer.write_u8('B');
streamer.write_u8('M');
streamer.write_u32(file_size);
streamer.write_u32(0);
- streamer.write_u32(PIXEL_DATA_OFFSET);
-
- streamer.write_u32(IMAGE_INFORMATION_SIZE); // Header size
- streamer.write_i32(bitmap->width()); // ImageWidth
- streamer.write_i32(bitmap->height()); // ImageHeight
- streamer.write_u16(1); // Planes
- streamer.write_u16(bytes_per_pixel * 8); // BitsPerPixel
- streamer.write_u32((u32)m_compression); // Compression
- streamer.write_u32(image_size); // ImageSize
- streamer.write_i32(0); // XpixelsPerMeter
- streamer.write_i32(0); // YpixelsPerMeter
- streamer.write_u32(0); // TotalColors
- streamer.write_u32(0); // ImportantColors
+ streamer.write_u32(pixel_data_offset);
+
+ streamer.write_u32((u32)dib_header); // Header size
+ streamer.write_i32(bitmap->width()); // ImageWidth
+ streamer.write_i32(bitmap->height()); // ImageHeight
+ streamer.write_u16(1); // Planes
+ streamer.write_u16(m_bytes_per_pixel * 8); // BitsPerPixel
+ streamer.write_u32((u32)m_compression); // Compression
+ streamer.write_u32(image_size); // ImageSize
+ streamer.write_i32(0); // XpixelsPerMeter
+ streamer.write_i32(0); // YpixelsPerMeter
+ streamer.write_u32(0); // TotalColors
+ streamer.write_u32(0); // ImportantColors
+
+ if (dib_header == DibHeader::V3 || dib_header == DibHeader::V4) {
+ streamer.write_u32(0x00ff0000); // Red bitmask
+ streamer.write_u32(0x0000ff00); // Green bitmask
+ streamer.write_u32(0x000000ff); // Blue bitmask
+ streamer.write_u32(0xff000000); // Alpha bitmask
+ }
+
+ if (dib_header == DibHeader::V4) {
+ streamer.write_u32(0); // Colorspace
+
+ for (int i = 0; i < 12; i++) {
+ streamer.write_u32(0); // Endpoints
+ }
+ }
buffer.append(pixel_data.data(), pixel_data.size());
return buffer;