diff options
author | AnotherTest <ali.mpfard@gmail.com> | 2020-11-07 23:07:03 +0330 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2020-11-08 21:46:13 +0100 |
commit | 705ad670f3609821be28be6b23e6ec8009f3ba16 (patch) | |
tree | a836cee370b6d2f7a1e6981370d8b92315debb78 /Libraries/LibGfx | |
parent | e23daa90a3924c9233e98241e8d97466b354ed6a (diff) | |
download | serenity-705ad670f3609821be28be6b23e6ec8009f3ba16.zip |
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.
Diffstat (limited to 'Libraries/LibGfx')
-rw-r--r-- | Libraries/LibGfx/Bitmap.cpp | 105 | ||||
-rw-r--r-- | Libraries/LibGfx/Bitmap.h | 2 |
2 files changed, 101 insertions, 6 deletions
diff --git a/Libraries/LibGfx/Bitmap.cpp b/Libraries/LibGfx/Bitmap.cpp index 21f7a67c0e..cd07ce0037 100644 --- a/Libraries/LibGfx/Bitmap.cpp +++ b/Libraries/LibGfx/Bitmap.cpp @@ -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>()) diff --git a/Libraries/LibGfx/Bitmap.h b/Libraries/LibGfx/Bitmap.h index 2aabb3e83e..493c3292f6 100644 --- a/Libraries/LibGfx/Bitmap.h +++ b/Libraries/LibGfx/Bitmap.h @@ -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; |