mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 20:57:35 +00: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
2 changed files with 101 additions and 6 deletions
|
@ -26,6 +26,7 @@
|
||||||
|
|
||||||
#include <AK/Checked.h>
|
#include <AK/Checked.h>
|
||||||
#include <AK/Memory.h>
|
#include <AK/Memory.h>
|
||||||
|
#include <AK/MemoryStream.h>
|
||||||
#include <AK/Optional.h>
|
#include <AK/Optional.h>
|
||||||
#include <AK/SharedBuffer.h>
|
#include <AK/SharedBuffer.h>
|
||||||
#include <AK/String.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, {});
|
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
|
// 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);
|
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) {
|
if (expected_size_min > actual_size || actual_size > expected_size_max) {
|
||||||
// Getting here is most likely an error.
|
// 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() << "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.";
|
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));
|
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)
|
Bitmap::Bitmap(BitmapFormat format, NonnullRefPtr<SharedBuffer>&& shared_buffer, const IntSize& size, const Vector<RGBA32>& palette)
|
||||||
: m_size(size)
|
: m_size(size)
|
||||||
, m_data(shared_buffer->data<void>())
|
, m_data(shared_buffer->data<void>())
|
||||||
|
|
|
@ -94,6 +94,7 @@ public:
|
||||||
static RefPtr<Bitmap> load_from_file(const StringView& path);
|
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&);
|
||||||
static RefPtr<Bitmap> create_with_shared_buffer(BitmapFormat, NonnullRefPtr<SharedBuffer>&&, const IntSize&, const Vector<RGBA32>& palette);
|
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)
|
static bool is_path_a_supported_image_format(const StringView& path)
|
||||||
{
|
{
|
||||||
#define __ENUMERATE_IMAGE_FORMAT(Name, Ext) \
|
#define __ENUMERATE_IMAGE_FORMAT(Name, Ext) \
|
||||||
|
@ -110,6 +111,7 @@ public:
|
||||||
RefPtr<Gfx::Bitmap> rotated(Gfx::RotationDirection) const;
|
RefPtr<Gfx::Bitmap> rotated(Gfx::RotationDirection) const;
|
||||||
RefPtr<Gfx::Bitmap> flipped(Gfx::Orientation) const;
|
RefPtr<Gfx::Bitmap> flipped(Gfx::Orientation) const;
|
||||||
RefPtr<Bitmap> to_bitmap_backed_by_shared_buffer() 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;
|
ShareableBitmap to_shareable_bitmap(pid_t peer_pid = -1) const;
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue