mirror of
https://github.com/RGBCube/serenity
synced 2025-07-27 02:37:36 +00:00
LibGfx/PortableFormat+image: Make encode
take a Stream
As we directly write to the stream, we don't need to store a copy of the entire image in memory. However, writing to a stream is heavier on the CPU than to a ByteBuffer. This commit unfortunately makes `add_pixels` two times slower.
This commit is contained in:
parent
af6dc267d3
commit
d4d3c3f262
3 changed files with 29 additions and 28 deletions
|
@ -5,47 +5,45 @@
|
|||
*/
|
||||
|
||||
#include "PortableFormatWriter.h"
|
||||
#include <AK/String.h>
|
||||
#include <AK/Stream.h>
|
||||
|
||||
namespace Gfx {
|
||||
|
||||
ErrorOr<ByteBuffer> PortableFormatWriter::encode(Bitmap const& bitmap, Options options)
|
||||
ErrorOr<void> PortableFormatWriter::encode(Stream& output, 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<void> 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()));
|
||||
TRY(add_header(output, options, bitmap.width(), bitmap.height(), 255));
|
||||
TRY(add_pixels(output, options, bitmap));
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
ErrorOr<void> PortableFormatWriter::add_pixels(ByteBuffer& buffer, Options const& options, Bitmap const& bitmap)
|
||||
ErrorOr<void> PortableFormatWriter::add_header(Stream& output, Options const& options, u32 width, u32 height, u32 maximal_value)
|
||||
{
|
||||
TRY(output.write_formatted("P{}\n", options.format == Options::Format::ASCII ? "3"sv : "6"sv));
|
||||
TRY(output.write_formatted("# {}\n", options.comment));
|
||||
TRY(output.write_formatted("{} {}\n", width, height));
|
||||
TRY(output.write_formatted("{}\n", maximal_value));
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
ErrorOr<void> PortableFormatWriter::add_pixels(Stream& output, 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()));
|
||||
TRY(output.write_formatted("{} {} {}\t", color.red(), color.green(), color.blue()));
|
||||
} else {
|
||||
TRY(buffer.try_append(color.red()));
|
||||
TRY(buffer.try_append(color.green()));
|
||||
TRY(buffer.try_append(color.blue()));
|
||||
TRY(output.write_value(color.red()));
|
||||
TRY(output.write_value(color.green()));
|
||||
TRY(output.write_value(color.blue()));
|
||||
}
|
||||
}
|
||||
if (options.format == Options::Format::ASCII)
|
||||
TRY(buffer.try_append('\n'));
|
||||
TRY(output.write_value('\n'));
|
||||
}
|
||||
|
||||
return {};
|
||||
|
|
|
@ -26,13 +26,13 @@ class PortableFormatWriter {
|
|||
public:
|
||||
using Options = PortableFormatWriterOptions;
|
||||
|
||||
static ErrorOr<ByteBuffer> encode(Bitmap const&, Options options = Options {});
|
||||
static ErrorOr<void> encode(Stream&, Bitmap const&, Options options = Options {});
|
||||
|
||||
private:
|
||||
PortableFormatWriter() = delete;
|
||||
|
||||
static ErrorOr<void> add_header(ByteBuffer&, Options const& options, u32 width, u32 height, u32 max_value);
|
||||
static ErrorOr<void> add_pixels(ByteBuffer&, Options const& options, Bitmap const&);
|
||||
static ErrorOr<void> add_header(Stream&, Options const& options, u32 width, u32 height, u32 max_value);
|
||||
static ErrorOr<void> add_pixels(Stream&, Options const& options, Bitmap const&);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -83,6 +83,9 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
|
|||
if (strip_color_profile)
|
||||
icc_data.clear();
|
||||
|
||||
auto output_stream = TRY(Core::File::open(out_path, Core::File::OpenMode::Write));
|
||||
auto buffered_stream = TRY(Core::OutputBufferedFile::create(move(output_stream)));
|
||||
|
||||
ByteBuffer bytes;
|
||||
if (out_path.ends_with(".bmp"sv, CaseSensitivity::CaseInsensitive)) {
|
||||
bytes = TRY(Gfx::BMPWriter::encode(*frame, { .icc_data = icc_data }));
|
||||
|
@ -90,7 +93,8 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
|
|||
bytes = TRY(Gfx::PNGWriter::encode(*frame, { .icc_data = icc_data }));
|
||||
} else if (out_path.ends_with(".ppm"sv, CaseSensitivity::CaseInsensitive)) {
|
||||
auto const format = ppm_ascii ? Gfx::PortableFormatWriter::Options::Format::ASCII : Gfx::PortableFormatWriter::Options::Format::Raw;
|
||||
bytes = TRY(Gfx::PortableFormatWriter::encode(*frame, { .format = format }));
|
||||
TRY(Gfx::PortableFormatWriter::encode(*buffered_stream, *frame, { .format = format }));
|
||||
return 0;
|
||||
} else if (out_path.ends_with(".qoi"sv, CaseSensitivity::CaseInsensitive)) {
|
||||
bytes = TRY(Gfx::QOIWriter::encode(*frame));
|
||||
} else {
|
||||
|
@ -98,8 +102,7 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
|
|||
return 1;
|
||||
}
|
||||
|
||||
auto output_stream = TRY(Core::File::open(out_path, Core::File::OpenMode::Write));
|
||||
TRY(output_stream->write_until_depleted(bytes));
|
||||
TRY(buffered_stream->write_until_depleted(bytes));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue