diff options
author | Lenny Maiorani <lenny@colorado.edu> | 2020-12-20 10:19:03 -0700 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2020-12-22 09:24:12 +0100 |
commit | a95d230a3ee2bf12f664a0e07bdecd5cc8d45841 (patch) | |
tree | cf85c0198a4c8d004698df9aad29d733881984b5 /Libraries/LibGfx/PPMLoader.cpp | |
parent | 6fac1abac493363b4d403fc06856608996ef7060 (diff) | |
download | serenity-a95d230a3ee2bf12f664a0e07bdecd5cc8d45841.zip |
LibGfx: Commonize functions in P*MLoader class implementations
Problem:
- Functions are duplicated in [PBM,PGM,PPM]Loader class
implementations. They are functionally equivalent. This does not
follow the DRY (Don't Repeat Yourself) principle.
Solution:
- Factor out the common functions into a separate file.
- Refactor common code to generic functions.
- Change `PPM_DEBUG` macro to be `PORTABLE_IMAGE_LOADER_DEBUG` to work
with all the supported types. This requires adding the image type to
the debug log messages for easier debugging.
Diffstat (limited to 'Libraries/LibGfx/PPMLoader.cpp')
-rw-r--r-- | Libraries/LibGfx/PPMLoader.cpp | 264 |
1 files changed, 15 insertions, 249 deletions
diff --git a/Libraries/LibGfx/PPMLoader.cpp b/Libraries/LibGfx/PPMLoader.cpp index a082054663..2fb2c1c909 100644 --- a/Libraries/LibGfx/PPMLoader.cpp +++ b/Libraries/LibGfx/PPMLoader.cpp @@ -25,6 +25,7 @@ */ #include "PPMLoader.h" +#include "PortableImageLoaderCommon.h" #include "Streamer.h" #include <AK/Endian.h> #include <AK/LexicalPath.h> @@ -33,15 +34,13 @@ #include <AK/StringBuilder.h> #include <string.h> -//#define PPM_DEBUG - namespace Gfx { struct PPMLoadingContext { enum Type { Unknown, - P3_ASCII, - P6_RAWBITS + ASCII, + RAWBITS }; enum State { @@ -55,6 +54,10 @@ struct PPMLoadingContext { Decoded }; + static constexpr auto ascii_magic_number = '3'; + static constexpr auto binary_magic_number = '6'; + static constexpr auto image_type = "PPM"; + Type type { Type::Unknown }; State state { State::NotDecoded }; const u8* data { nullptr }; @@ -65,178 +68,12 @@ struct PPMLoadingContext { RefPtr<Gfx::Bitmap> bitmap; }; -ALWAYS_INLINE static Color adjust_color(u16 max_val, Color& color) -{ - color.set_red((color.red() * 255) / max_val); - color.set_green((color.green() * 255) / max_val); - color.set_blue((color.blue() * 255) / max_val); - - return color; -} - -static bool read_number(Streamer& streamer, u16* value) -{ - u8 byte; - StringBuilder sb; - - while (streamer.read(byte)) { - if (byte == ' ' || byte == '\t' || byte == '\n' || byte == '\r') { - streamer.step_back(); - break; - } - - sb.append(byte); - } - - auto opt_value = sb.to_string().to_uint(); - if (!opt_value.has_value()) { - return false; - } - - *value = (u16)opt_value.value(); - return true; -} - -static bool read_comment([[maybe_unused]] PPMLoadingContext& context, Streamer& streamer) -{ - bool exist = false; - u8 byte; - - while (streamer.read(byte)) { - switch (byte) { - case '#': { - exist = true; - break; - } - case '\t': - case '\n': { - return exist; - } - default: - break; - } - } - - return exist; -} - -static bool read_magic_number(PPMLoadingContext& context, Streamer& streamer) -{ - if (context.state >= PPMLoadingContext::MagicNumber) - return true; - - if (!context.data || context.data_size < 2) { - context.state = PPMLoadingContext::State::Error; -#ifdef PPM_DEBUG - dbg() << "There is not enough data."; -#endif - return false; - } - - u8 magic_number[2]; - if (!streamer.read_bytes(magic_number, 2)) { - context.state = PPMLoadingContext::State::Error; -#ifdef PPM_DEBUG - dbg() << "We can't read magic number."; -#endif - return false; - } - - if (magic_number[0] == 'P' && magic_number[1] == '3') { - context.type = PPMLoadingContext::P3_ASCII; - context.state = PPMLoadingContext::MagicNumber; - return true; - } - - if (magic_number[0] == 'P' && magic_number[1] == '6') { - context.type = PPMLoadingContext::P6_RAWBITS; - context.state = PPMLoadingContext::MagicNumber; - return true; - } - - context.state = PPMLoadingContext::State::Error; -#ifdef PPM_DEBUG - dbg() << "Magic number is not valid." << (char)magic_number[0] << (char)magic_number[1]; -#endif - return false; -} - -static bool read_white_space(PPMLoadingContext& context, Streamer& streamer) -{ - bool exist = false; - u8 byte; - - while (streamer.read(byte)) { - switch (byte) { - case ' ': - case '\t': - case '\n': - case '\r': { - exist = true; - break; - } - case '#': { - streamer.step_back(); - read_comment(context, streamer); - break; - } - default: { - streamer.step_back(); - return exist; - } - } - } - - return exist; -} - -static bool read_width(PPMLoadingContext& context, Streamer& streamer) -{ - bool result = read_number(streamer, &context.width); - if (!result || context.width == 0) { - return false; - } - - context.state = PPMLoadingContext::Width; - return true; -} - -static bool read_height(PPMLoadingContext& context, Streamer& streamer) -{ - bool result = read_number(streamer, &context.height); - if (!result || context.height == 0) { - return false; - } - - context.state = PPMLoadingContext::Height; - return true; -} - -static bool read_max_val(PPMLoadingContext& context, Streamer& streamer) -{ - bool result = read_number(streamer, &context.max_val); - if (!result || context.max_val == 0) { - return false; - } - - if (context.max_val > 255) { -#ifdef PPM_DEBUG - dbg() << "We can't parse 2 byte color."; -#endif - context.state = PPMLoadingContext::Error; - return false; - } - - context.state = PPMLoadingContext::Maxval; - return true; -} - static bool read_image_data(PPMLoadingContext& context, Streamer& streamer) { Vector<Gfx::Color> color_data; color_data.ensure_capacity(context.width * context.height); - if (context.type == PPMLoadingContext::P3_ASCII) { + if (context.type == PPMLoadingContext::ASCII) { u16 red; u16 green; u16 blue; @@ -265,7 +102,7 @@ static bool read_image_data(PPMLoadingContext& context, Streamer& streamer) color = adjust_color(context.max_val, color); color_data.append(color); } - } else if (context.type == PPMLoadingContext::P6_RAWBITS) { + } else if (context.type == PPMLoadingContext::RAWBITS) { u8 pixel[3]; while (streamer.read_bytes(pixel, 3)) { color_data.append({ pixel[0], pixel[1], pixel[2] }); @@ -275,95 +112,24 @@ static bool read_image_data(PPMLoadingContext& context, Streamer& streamer) if (context.width * context.height != color_data.size()) return false; - context.bitmap = Bitmap::create_purgeable(BitmapFormat::RGB32, { context.width, context.height }); - if (!context.bitmap) { - context.state = PPMLoadingContext::State::Error; + if (!create_bitmap(context)) { return false; } - size_t index = 0; - for (int y = 0; y < context.height; ++y) { - for (int x = 0; x < context.width; ++x) { - context.bitmap->set_pixel(x, y, color_data.at(index)); - index++; - } - } + set_pixels(context, color_data); context.state = PPMLoadingContext::State::Bitmap; return true; } -static bool decode_ppm(PPMLoadingContext& context) -{ - if (context.state >= PPMLoadingContext::State::Decoded) - return true; - - auto error_guard = ArmedScopeGuard([&] { - context.state = PPMLoadingContext::State::Error; - }); - - Streamer streamer(context.data, context.data_size); - - if (!read_magic_number(context, streamer)) - return false; - - if (!read_white_space(context, streamer)) - return false; - - if (!read_width(context, streamer)) - return false; - - if (!read_white_space(context, streamer)) - return false; - - if (!read_height(context, streamer)) - return false; - - if (!read_white_space(context, streamer)) - return false; - - if (!read_max_val(context, streamer)) - return false; - - if (!read_white_space(context, streamer)) - return false; - - if (!read_image_data(context, streamer)) - return false; - - error_guard.disarm(); - context.state = PPMLoadingContext::State::Decoded; - return true; -} - -static RefPtr<Gfx::Bitmap> load_ppm_impl(const u8* data, size_t data_size) -{ - PPMLoadingContext context; - context.data = data; - context.data_size = data_size; - - if (!decode_ppm(context)) - return nullptr; - - return context.bitmap; -} - RefPtr<Gfx::Bitmap> load_ppm(const StringView& path) { - MappedFile mapped_file(path); - if (!mapped_file.is_valid()) { - return nullptr; - } - - auto bitmap = load_ppm_impl((const u8*)mapped_file.data(), mapped_file.size()); - if (bitmap) - bitmap->set_mmap_name(String::format("Gfx::Bitmap [%dx%d] - Decoded PPM: %s", bitmap->width(), bitmap->height(), LexicalPath::canonicalized_path(path).characters())); - return bitmap; + return load<PPMLoadingContext>(path); } RefPtr<Gfx::Bitmap> load_ppm_from_memory(const u8* data, size_t length) { - auto bitmap = load_ppm_impl(data, length); + auto bitmap = load_impl<PPMLoadingContext>(data, length); if (bitmap) bitmap->set_mmap_name(String::format("Gfx::Bitmap [%dx%d] - Decoded PPM: <memory>", bitmap->width(), bitmap->height())); return bitmap; @@ -386,7 +152,7 @@ IntSize PPMImageDecoderPlugin::size() return {}; if (m_context->state < PPMLoadingContext::State::Decoded) { - bool success = decode_ppm(*m_context); + bool success = decode(*m_context); if (!success) return {}; } @@ -400,7 +166,7 @@ RefPtr<Gfx::Bitmap> PPMImageDecoderPlugin::bitmap() return nullptr; if (m_context->state < PPMLoadingContext::State::Decoded) { - bool success = decode_ppm(*m_context); + bool success = decode(*m_context); if (!success) return nullptr; } |