diff --git a/Userland/Libraries/LibGfx/CMakeLists.txt b/Userland/Libraries/LibGfx/CMakeLists.txt index 5ffa912f9f..259dd78fc9 100644 --- a/Userland/Libraries/LibGfx/CMakeLists.txt +++ b/Userland/Libraries/LibGfx/CMakeLists.txt @@ -41,6 +41,7 @@ set(SOURCES PGMLoader.cpp PNGLoader.cpp PNGWriter.cpp + PortableFormatWriter.cpp PPMLoader.cpp Painter.cpp Palette.cpp diff --git a/Userland/Libraries/LibGfx/PortableFormatWriter.cpp b/Userland/Libraries/LibGfx/PortableFormatWriter.cpp new file mode 100644 index 0000000000..56bf8b0bd6 --- /dev/null +++ b/Userland/Libraries/LibGfx/PortableFormatWriter.cpp @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2023, Lucas Chollet + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include "PortableFormatWriter.h" +#include + +namespace Gfx { + +ErrorOr PortableFormatWriter::encode(Bitmap const& bitmap, Options options) +{ + ByteBuffer buffer; + + // FIXME: Add support for PBM and PGM + + TRY(add_header(buffer, options, bitmap.width(), bitmap.height(), 255)); + TRY(add_pixels(buffer, options, bitmap)); + + return buffer; +} + +ErrorOr PortableFormatWriter::add_header(ByteBuffer& buffer, Options const& options, u32 width, u32 height, u32 maximal_value) +{ + TRY(buffer.try_append(TRY(String::formatted("P{}\n", options.format == Options::Format::ASCII ? "3"sv : "6"sv)).bytes())); + TRY(buffer.try_append(TRY(String::formatted("# {}\n", options.comment)).bytes())); + TRY(buffer.try_append(TRY(String::formatted("{} {}\n", width, height)).bytes())); + TRY(buffer.try_append(TRY(String::formatted("{}\n", maximal_value)).bytes())); + + return {}; +} + +ErrorOr PortableFormatWriter::add_pixels(ByteBuffer& buffer, Options const& options, Bitmap const& bitmap) +{ + for (int i = 0; i < bitmap.height(); ++i) { + for (int j = 0; j < bitmap.width(); ++j) { + auto color = bitmap.get_pixel(j, i); + if (options.format == Options::Format::ASCII) { + TRY(buffer.try_append(TRY(String::formatted("{} {} {}\t", color.red(), color.green(), color.blue())).bytes())); + } else { + TRY(buffer.try_append(color.red())); + TRY(buffer.try_append(color.green())); + TRY(buffer.try_append(color.blue())); + } + } + if (options.format == Options::Format::ASCII) + TRY(buffer.try_append('\n')); + } + + return {}; +} + +} diff --git a/Userland/Libraries/LibGfx/PortableFormatWriter.h b/Userland/Libraries/LibGfx/PortableFormatWriter.h new file mode 100644 index 0000000000..30da31a703 --- /dev/null +++ b/Userland/Libraries/LibGfx/PortableFormatWriter.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2023, Lucas Chollet + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include + +namespace Gfx { + +// This is not a nested struct to work around https://llvm.org/PR36684 +struct PortableFormatWriterOptions { + enum class Format { + ASCII, + Raw, + }; + + Format format = Format::Raw; + StringView comment = "Generated with SerenityOS - LibGfx."sv; +}; + +class PortableFormatWriter { +public: + using Options = PortableFormatWriterOptions; + + static ErrorOr encode(Bitmap const&, Options options = Options {}); + +private: + PortableFormatWriter() = delete; + + static ErrorOr add_header(ByteBuffer&, Options const& options, u32 width, u32 height, u32 max_value); + static ErrorOr add_pixels(ByteBuffer&, Options const& options, Bitmap const&); +}; + +}