mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-01-08 20:32:56 +03:00
LibGfx: Add methods to serialise and deserialise a Bitmap
Unlike `to_shared_buffer()` and co, these methods do *not* require extra metadata about the bitmap.
This commit is contained in:
parent
e23daa90a3
commit
705ad670f3
Notes:
sideshowbarker
2024-07-19 01:30:08 +09:00
Author: https://github.com/alimpfard Commit: https://github.com/SerenityOS/serenity/commit/705ad670f36 Pull-request: https://github.com/SerenityOS/serenity/pull/3984 Issue: https://github.com/SerenityOS/serenity/issues/3906 Reviewed-by: https://github.com/awesomekling
@ -26,6 +26,7 @@
|
||||
|
||||
#include <AK/Checked.h>
|
||||
#include <AK/Memory.h>
|
||||
#include <AK/MemoryStream.h>
|
||||
#include <AK/Optional.h>
|
||||
#include <AK/SharedBuffer.h>
|
||||
#include <AK/String.h>
|
||||
@ -148,25 +149,117 @@ RefPtr<Bitmap> Bitmap::create_with_shared_buffer(BitmapFormat format, NonnullRef
|
||||
return create_with_shared_buffer(format, move(shared_buffer), size, {});
|
||||
}
|
||||
|
||||
RefPtr<Bitmap> Bitmap::create_with_shared_buffer(BitmapFormat format, NonnullRefPtr<SharedBuffer>&& shared_buffer, const IntSize& size, const Vector<RGBA32>& palette)
|
||||
static bool check_size(const IntSize& size, BitmapFormat format, unsigned actual_size)
|
||||
{
|
||||
if (size_would_overflow(format, size))
|
||||
return nullptr;
|
||||
|
||||
unsigned actual_size = shared_buffer->size();
|
||||
// FIXME: Code duplication of size_in_bytes() and m_pitch
|
||||
unsigned expected_size_min = minimum_pitch(size.width(), format) * size.height();
|
||||
unsigned expected_size_min = Bitmap::minimum_pitch(size.width(), format) * size.height();
|
||||
unsigned expected_size_max = round_up_to_power_of_two(expected_size_min, PAGE_SIZE);
|
||||
if (expected_size_min > actual_size || actual_size > expected_size_max) {
|
||||
// Getting here is most likely an error.
|
||||
dbg() << "Constructing a shared bitmap for format " << (int)format << " and size " << size << ", which demands " << expected_size_min << " bytes, which rounds up to at most " << expected_size_max << ".";
|
||||
dbg() << "However, we were given " << actual_size << " bytes, which is outside this range?! Refusing cowardly.";
|
||||
return {};
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
RefPtr<Bitmap> Bitmap::create_with_shared_buffer(BitmapFormat format, NonnullRefPtr<SharedBuffer>&& shared_buffer, const IntSize& size, const Vector<RGBA32>& palette)
|
||||
{
|
||||
if (size_would_overflow(format, size))
|
||||
return nullptr;
|
||||
|
||||
if (!check_size(size, format, shared_buffer->size()))
|
||||
return {};
|
||||
|
||||
return adopt(*new Bitmap(format, move(shared_buffer), size, palette));
|
||||
}
|
||||
|
||||
/// Read a bitmap as described by:
|
||||
/// - actual size
|
||||
/// - width
|
||||
/// - height
|
||||
/// - format
|
||||
/// - palette count
|
||||
/// - palette data (= palette count * RGBA32)
|
||||
/// - image data (= actual size * u8)
|
||||
RefPtr<Bitmap> Bitmap::create_from_serialized_byte_buffer(ByteBuffer&& buffer)
|
||||
{
|
||||
InputMemoryStream stream { buffer };
|
||||
unsigned actual_size;
|
||||
unsigned width;
|
||||
unsigned height;
|
||||
BitmapFormat format;
|
||||
unsigned palette_size;
|
||||
Vector<RGBA32> palette;
|
||||
|
||||
auto read = [&]<typename T>(T& value) {
|
||||
if (stream.read({ &value, sizeof(T) }) != sizeof(T))
|
||||
return false;
|
||||
return true;
|
||||
};
|
||||
|
||||
if (!read(actual_size) || !read(width) || !read(height) || !read(format) || !read(palette_size))
|
||||
return nullptr;
|
||||
|
||||
if (format > BitmapFormat::RGBA32 || format < BitmapFormat::Indexed1)
|
||||
return nullptr;
|
||||
|
||||
if (!check_size({ width, height }, format, actual_size))
|
||||
return {};
|
||||
|
||||
palette.ensure_capacity(palette_size);
|
||||
for (size_t i = 0; i < palette_size; ++i) {
|
||||
if (!read(palette[i]))
|
||||
return {};
|
||||
}
|
||||
|
||||
if (stream.remaining() < actual_size)
|
||||
return {};
|
||||
|
||||
auto data = stream.bytes().slice(stream.offset(), actual_size);
|
||||
|
||||
auto bitmap = Bitmap::create(format, { width, height });
|
||||
if (!bitmap)
|
||||
return {};
|
||||
|
||||
bitmap->m_palette = new RGBA32[palette_size];
|
||||
memcpy(bitmap->m_palette, palette.data(), palette_size * sizeof(RGBA32));
|
||||
|
||||
data.copy_to({ bitmap->scanline(0), bitmap->size_in_bytes() });
|
||||
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
ByteBuffer Bitmap::serialize_to_byte_buffer() const
|
||||
{
|
||||
auto buffer = ByteBuffer::create_uninitialized(4 * sizeof(unsigned) + sizeof(BitmapFormat) + sizeof(RGBA32) * palette_size(m_format) + size_in_bytes());
|
||||
OutputMemoryStream stream { buffer };
|
||||
|
||||
auto write = [&]<typename T>(T value) {
|
||||
if (stream.write({ &value, sizeof(T) }) != sizeof(T))
|
||||
return false;
|
||||
return true;
|
||||
};
|
||||
|
||||
auto palette = palette_to_vector();
|
||||
|
||||
if (!write(size_in_bytes()) || !write((unsigned)size().width()) || !write((unsigned)size().height()) || !write(m_format) || !write((unsigned)palette.size()))
|
||||
return {};
|
||||
|
||||
for (auto& p : palette) {
|
||||
if (!write(p))
|
||||
return {};
|
||||
}
|
||||
|
||||
auto size = size_in_bytes();
|
||||
ASSERT(stream.remaining() == size);
|
||||
if (stream.write({ scanline(0), size }) != size)
|
||||
return {};
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
Bitmap::Bitmap(BitmapFormat format, NonnullRefPtr<SharedBuffer>&& shared_buffer, const IntSize& size, const Vector<RGBA32>& palette)
|
||||
: m_size(size)
|
||||
, m_data(shared_buffer->data<void>())
|
||||
|
@ -94,6 +94,7 @@ public:
|
||||
static RefPtr<Bitmap> load_from_file(const StringView& path);
|
||||
static RefPtr<Bitmap> create_with_shared_buffer(BitmapFormat, NonnullRefPtr<SharedBuffer>&&, const IntSize&);
|
||||
static RefPtr<Bitmap> create_with_shared_buffer(BitmapFormat, NonnullRefPtr<SharedBuffer>&&, const IntSize&, const Vector<RGBA32>& palette);
|
||||
static RefPtr<Bitmap> create_from_serialized_byte_buffer(ByteBuffer&& buffer);
|
||||
static bool is_path_a_supported_image_format(const StringView& path)
|
||||
{
|
||||
#define __ENUMERATE_IMAGE_FORMAT(Name, Ext) \
|
||||
@ -110,6 +111,7 @@ public:
|
||||
RefPtr<Gfx::Bitmap> rotated(Gfx::RotationDirection) const;
|
||||
RefPtr<Gfx::Bitmap> flipped(Gfx::Orientation) const;
|
||||
RefPtr<Bitmap> to_bitmap_backed_by_shared_buffer() const;
|
||||
ByteBuffer serialize_to_byte_buffer() const;
|
||||
|
||||
ShareableBitmap to_shareable_bitmap(pid_t peer_pid = -1) const;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user