summaryrefslogtreecommitdiff
path: root/Libraries/LibGfx
diff options
context:
space:
mode:
authorAnotherTest <ali.mpfard@gmail.com>2020-11-07 23:07:03 +0330
committerAndreas Kling <kling@serenityos.org>2020-11-08 21:46:13 +0100
commit705ad670f3609821be28be6b23e6ec8009f3ba16 (patch)
treea836cee370b6d2f7a1e6981370d8b92315debb78 /Libraries/LibGfx
parente23daa90a3924c9233e98241e8d97466b354ed6a (diff)
downloadserenity-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.cpp105
-rw-r--r--Libraries/LibGfx/Bitmap.h2
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;