1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-31 09:48:11 +00:00

LibGfx: Add BMP loader

Adds an *almost fully featured BMP loader to process .bmp files.

Features:
- All header formats are supported
- Full RLE4/8/24 support
- Color scaling (e.g. distributing a 5-bit color throughout the 8-bit
color spectrum, so 5-bit white is still 0xffffff)
- Full BITMASK/ALPHABITMASK support

*Not included:
- 1D Huffman compression. Good luck actually finding a bmp in the wild
that uses this
- Use of any field in the V4/V5 header. Color spaces? Endpoints? No
thanks :)

This loader was tested with the images at
https://entropymine.com/jason/bmpsuite/bmpsuite/html/bmpsuite.html. This
loader correctly displays 81 out of the 90 total images (for reference,
firefox displays 64 correctly). Note that not rendering the images at
the bottom is counted as displaying correctly.
This commit is contained in:
Matthew Olsson 2020-06-17 12:37:16 -07:00 committed by Andreas Kling
parent dfe5b232f4
commit 4e093a7c23
8 changed files with 1477 additions and 15 deletions

View file

@ -29,14 +29,13 @@
#include <AK/SharedBuffer.h>
#include <AK/String.h>
#include <LibGfx/Bitmap.h>
#include <LibGfx/BMPLoader.h>
#include <LibGfx/GIFLoader.h>
#include <LibGfx/PNGLoader.h>
#include <LibGfx/ShareableBitmap.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <sys/mman.h>
#include <unistd.h>
namespace Gfx {
@ -69,8 +68,7 @@ Bitmap::Bitmap(BitmapFormat format, const IntSize& size, Purgeable purgeable)
{
ASSERT(!m_size.is_empty());
ASSERT(!size_would_overflow(format, size));
if (format == BitmapFormat::Indexed8)
m_palette = new RGBA32[256];
allocate_palette_from_format(format);
int map_flags = purgeable == Purgeable::Yes ? (MAP_PURGEABLE | MAP_PRIVATE) : (MAP_ANONYMOUS | MAP_PRIVATE);
m_data = (RGBA32*)mmap_with_name(nullptr, size_in_bytes(), PROT_READ | PROT_WRITE, map_flags, 0, 0, String::format("GraphicsBitmap [%dx%d]", width(), height()).characters());
ASSERT(m_data && m_data != (void*)-1);
@ -102,8 +100,7 @@ Bitmap::Bitmap(BitmapFormat format, const IntSize& size, size_t pitch, RGBA32* d
, m_format(format)
{
ASSERT(!size_would_overflow(format, size));
if (format == BitmapFormat::Indexed8)
m_palette = new RGBA32[256];
allocate_palette_from_format(format);
}
RefPtr<Bitmap> Bitmap::create_with_shared_buffer(BitmapFormat format, NonnullRefPtr<SharedBuffer>&& shared_buffer, const IntSize& size)
@ -120,7 +117,7 @@ Bitmap::Bitmap(BitmapFormat format, NonnullRefPtr<SharedBuffer>&& shared_buffer,
, m_format(format)
, m_shared_buffer(move(shared_buffer))
{
ASSERT(format != BitmapFormat::Indexed8);
ASSERT(!is_indexed(format));
ASSERT(!size_would_overflow(format, size));
}
@ -200,7 +197,7 @@ void Bitmap::set_mmap_name(const StringView& name)
void Bitmap::fill(Color color)
{
ASSERT(m_format == BitmapFormat::RGB32 || m_format == BitmapFormat::RGBA32);
ASSERT(!is_indexed(m_format));
for (int y = 0; y < height(); ++y) {
auto* scanline = this->scanline(y);
fast_u32_fill(scanline, color.value(), width());
@ -249,4 +246,17 @@ ShareableBitmap Bitmap::to_shareable_bitmap(pid_t peer_pid) const
return ShareableBitmap(*bitmap);
}
void Bitmap::allocate_palette_from_format(BitmapFormat format)
{
if (format == BitmapFormat::Indexed1) {
m_palette = new RGBA32[2];
} else if (format == BitmapFormat::Indexed2) {
m_palette = new RGBA32[4];
} else if (format == BitmapFormat::Indexed4) {
m_palette = new RGBA32[16];
} else if (format == BitmapFormat::Indexed8) {
m_palette = new RGBA32[256];
}
}
}