mirror of
https://github.com/fergalmoran/ladybird.git
synced 2025-12-22 09:19:03 +00:00
LibGfx: Remove TGA image format support
This format is not supported by other browsers.
This commit is contained in:
committed by
Andreas Kling
parent
681a2ac14e
commit
b7f8d7aec5
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 64 KiB |
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 64 KiB |
@@ -1,20 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2022, Liav A. <liavalb@hotmail.co.il>
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <LibGfx/ImageFormats/TGALoader.h>
|
|
||||||
#include <stddef.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
extern "C" int LLVMFuzzerTestOneInput(uint8_t const* data, size_t size)
|
|
||||||
{
|
|
||||||
AK::set_debug_enabled(false);
|
|
||||||
auto decoder_or_error = Gfx::TGAImageDecoderPlugin::create({ data, size });
|
|
||||||
if (decoder_or_error.is_error())
|
|
||||||
return 0;
|
|
||||||
auto decoder = decoder_or_error.release_value();
|
|
||||||
(void)decoder->frame(0);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@@ -38,7 +38,6 @@ set(FUZZER_TARGETS
|
|||||||
SHA512
|
SHA512
|
||||||
Tar
|
Tar
|
||||||
TextDecoder
|
TextDecoder
|
||||||
TGALoader
|
|
||||||
TIFFLoader
|
TIFFLoader
|
||||||
TTF
|
TTF
|
||||||
TinyVGLoader
|
TinyVGLoader
|
||||||
@@ -97,7 +96,6 @@ set(FUZZER_DEPENDENCIES_SHA384 LibCrypto)
|
|||||||
set(FUZZER_DEPENDENCIES_SHA512 LibCrypto)
|
set(FUZZER_DEPENDENCIES_SHA512 LibCrypto)
|
||||||
set(FUZZER_DEPENDENCIES_Tar LibArchive)
|
set(FUZZER_DEPENDENCIES_Tar LibArchive)
|
||||||
set(FUZZER_DEPENDENCIES_TextDecoder LibTextCodec)
|
set(FUZZER_DEPENDENCIES_TextDecoder LibTextCodec)
|
||||||
set(FUZZER_DEPENDENCIES_TGALoader LibGfx)
|
|
||||||
set(FUZZER_DEPENDENCIES_TIFFLoader LibGfx)
|
set(FUZZER_DEPENDENCIES_TIFFLoader LibGfx)
|
||||||
set(FUZZER_DEPENDENCIES_TTF LibGfx)
|
set(FUZZER_DEPENDENCIES_TTF LibGfx)
|
||||||
set(FUZZER_DEPENDENCIES_TinyVGLoader LibGfx)
|
set(FUZZER_DEPENDENCIES_TinyVGLoader LibGfx)
|
||||||
|
|||||||
@@ -76,7 +76,6 @@ shared_library("LibGfx") {
|
|||||||
"ImageFormats/PNGLoader.cpp",
|
"ImageFormats/PNGLoader.cpp",
|
||||||
"ImageFormats/PNGWriter.cpp",
|
"ImageFormats/PNGWriter.cpp",
|
||||||
"ImageFormats/QMArithmeticDecoder.cpp",
|
"ImageFormats/QMArithmeticDecoder.cpp",
|
||||||
"ImageFormats/TGALoader.cpp",
|
|
||||||
"ImageFormats/TIFFLoader.cpp",
|
"ImageFormats/TIFFLoader.cpp",
|
||||||
"ImageFormats/TinyVGLoader.cpp",
|
"ImageFormats/TinyVGLoader.cpp",
|
||||||
"ImageFormats/WebPLoader.cpp",
|
"ImageFormats/WebPLoader.cpp",
|
||||||
|
|||||||
@@ -18,7 +18,6 @@
|
|||||||
#include <LibGfx/ImageFormats/JPEGXLLoader.h>
|
#include <LibGfx/ImageFormats/JPEGXLLoader.h>
|
||||||
#include <LibGfx/ImageFormats/PNGLoader.h>
|
#include <LibGfx/ImageFormats/PNGLoader.h>
|
||||||
#include <LibGfx/ImageFormats/QMArithmeticDecoder.h>
|
#include <LibGfx/ImageFormats/QMArithmeticDecoder.h>
|
||||||
#include <LibGfx/ImageFormats/TGALoader.h>
|
|
||||||
#include <LibGfx/ImageFormats/TIFFLoader.h>
|
#include <LibGfx/ImageFormats/TIFFLoader.h>
|
||||||
#include <LibGfx/ImageFormats/TIFFMetadata.h>
|
#include <LibGfx/ImageFormats/TIFFMetadata.h>
|
||||||
#include <LibGfx/ImageFormats/TinyVGLoader.h>
|
#include <LibGfx/ImageFormats/TinyVGLoader.h>
|
||||||
@@ -726,42 +725,6 @@ TEST_CASE(test_png_malformed_frame)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE(test_targa_bottom_left)
|
|
||||||
{
|
|
||||||
auto file = TRY_OR_FAIL(Core::MappedFile::map(TEST_INPUT("tga/buggie-bottom-left-uncompressed.tga"sv)));
|
|
||||||
EXPECT(Gfx::TGAImageDecoderPlugin::validate_before_create(file->bytes()));
|
|
||||||
auto plugin_decoder = TRY_OR_FAIL(Gfx::TGAImageDecoderPlugin::create(file->bytes()));
|
|
||||||
|
|
||||||
TRY_OR_FAIL(expect_single_frame(*plugin_decoder));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE(test_targa_top_left)
|
|
||||||
{
|
|
||||||
auto file = TRY_OR_FAIL(Core::MappedFile::map(TEST_INPUT("tga/buggie-top-left-uncompressed.tga"sv)));
|
|
||||||
EXPECT(Gfx::TGAImageDecoderPlugin::validate_before_create(file->bytes()));
|
|
||||||
auto plugin_decoder = TRY_OR_FAIL(Gfx::TGAImageDecoderPlugin::create(file->bytes()));
|
|
||||||
|
|
||||||
TRY_OR_FAIL(expect_single_frame(*plugin_decoder));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE(test_targa_bottom_left_compressed)
|
|
||||||
{
|
|
||||||
auto file = TRY_OR_FAIL(Core::MappedFile::map(TEST_INPUT("tga/buggie-bottom-left-compressed.tga"sv)));
|
|
||||||
EXPECT(Gfx::TGAImageDecoderPlugin::validate_before_create(file->bytes()));
|
|
||||||
auto plugin_decoder = TRY_OR_FAIL(Gfx::TGAImageDecoderPlugin::create(file->bytes()));
|
|
||||||
|
|
||||||
TRY_OR_FAIL(expect_single_frame(*plugin_decoder));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE(test_targa_top_left_compressed)
|
|
||||||
{
|
|
||||||
auto file = TRY_OR_FAIL(Core::MappedFile::map(TEST_INPUT("tga/buggie-top-left-compressed.tga"sv)));
|
|
||||||
EXPECT(Gfx::TGAImageDecoderPlugin::validate_before_create(file->bytes()));
|
|
||||||
auto plugin_decoder = TRY_OR_FAIL(Gfx::TGAImageDecoderPlugin::create(file->bytes()));
|
|
||||||
|
|
||||||
TRY_OR_FAIL(expect_single_frame(*plugin_decoder));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE(test_tiff_uncompressed)
|
TEST_CASE(test_tiff_uncompressed)
|
||||||
{
|
{
|
||||||
auto file = TRY_OR_FAIL(Core::MappedFile::map(TEST_INPUT("tiff/uncompressed.tiff"sv)));
|
auto file = TRY_OR_FAIL(Core::MappedFile::map(TEST_INPUT("tiff/uncompressed.tiff"sv)));
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 64 KiB |
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 64 KiB |
@@ -54,7 +54,6 @@ set(SOURCES
|
|||||||
ImageFormats/PNGLoader.cpp
|
ImageFormats/PNGLoader.cpp
|
||||||
ImageFormats/PNGWriter.cpp
|
ImageFormats/PNGWriter.cpp
|
||||||
ImageFormats/QMArithmeticDecoder.cpp
|
ImageFormats/QMArithmeticDecoder.cpp
|
||||||
ImageFormats/TGALoader.cpp
|
|
||||||
ImageFormats/TIFFLoader.cpp
|
ImageFormats/TIFFLoader.cpp
|
||||||
ImageFormats/TinyVGLoader.cpp
|
ImageFormats/TinyVGLoader.cpp
|
||||||
ImageFormats/WebPLoader.cpp
|
ImageFormats/WebPLoader.cpp
|
||||||
|
|||||||
@@ -15,7 +15,6 @@
|
|||||||
#include <LibGfx/ImageFormats/JPEGLoader.h>
|
#include <LibGfx/ImageFormats/JPEGLoader.h>
|
||||||
#include <LibGfx/ImageFormats/JPEGXLLoader.h>
|
#include <LibGfx/ImageFormats/JPEGXLLoader.h>
|
||||||
#include <LibGfx/ImageFormats/PNGLoader.h>
|
#include <LibGfx/ImageFormats/PNGLoader.h>
|
||||||
#include <LibGfx/ImageFormats/TGALoader.h>
|
|
||||||
#include <LibGfx/ImageFormats/TIFFLoader.h>
|
#include <LibGfx/ImageFormats/TIFFLoader.h>
|
||||||
#include <LibGfx/ImageFormats/TinyVGLoader.h>
|
#include <LibGfx/ImageFormats/TinyVGLoader.h>
|
||||||
#include <LibGfx/ImageFormats/WebPLoader.h>
|
#include <LibGfx/ImageFormats/WebPLoader.h>
|
||||||
@@ -53,39 +52,11 @@ static ErrorOr<OwnPtr<ImageDecoderPlugin>> probe_and_sniff_for_appropriate_plugi
|
|||||||
return OwnPtr<ImageDecoderPlugin> {};
|
return OwnPtr<ImageDecoderPlugin> {};
|
||||||
}
|
}
|
||||||
|
|
||||||
static ErrorOr<OwnPtr<ImageDecoderPlugin>> probe_and_sniff_for_appropriate_plugin_with_known_mime_type(StringView mime_type, ReadonlyBytes bytes)
|
ErrorOr<RefPtr<ImageDecoder>> ImageDecoder::try_create_for_raw_bytes(ReadonlyBytes bytes, [[maybe_unused]] Optional<ByteString> mime_type)
|
||||||
{
|
|
||||||
struct ImagePluginWithMIMETypeInitializer {
|
|
||||||
bool (*validate_before_create)(ReadonlyBytes) = nullptr;
|
|
||||||
ErrorOr<NonnullOwnPtr<ImageDecoderPlugin>> (*create)(ReadonlyBytes) = nullptr;
|
|
||||||
StringView mime_type;
|
|
||||||
};
|
|
||||||
|
|
||||||
static constexpr ImagePluginWithMIMETypeInitializer s_initializers_with_mime_type[] = {
|
|
||||||
{ TGAImageDecoderPlugin::validate_before_create, TGAImageDecoderPlugin::create, "image/x-targa"sv },
|
|
||||||
};
|
|
||||||
|
|
||||||
for (auto& plugin : s_initializers_with_mime_type) {
|
|
||||||
if (plugin.mime_type != mime_type)
|
|
||||||
continue;
|
|
||||||
auto validation_result = plugin.validate_before_create(bytes);
|
|
||||||
if (!validation_result)
|
|
||||||
continue;
|
|
||||||
return TRY(plugin.create(bytes));
|
|
||||||
}
|
|
||||||
return OwnPtr<ImageDecoderPlugin> {};
|
|
||||||
}
|
|
||||||
|
|
||||||
ErrorOr<RefPtr<ImageDecoder>> ImageDecoder::try_create_for_raw_bytes(ReadonlyBytes bytes, Optional<ByteString> mime_type)
|
|
||||||
{
|
{
|
||||||
if (auto plugin = TRY(probe_and_sniff_for_appropriate_plugin(bytes)); plugin)
|
if (auto plugin = TRY(probe_and_sniff_for_appropriate_plugin(bytes)); plugin)
|
||||||
return adopt_ref_if_nonnull(new (nothrow) ImageDecoder(plugin.release_nonnull()));
|
return adopt_ref_if_nonnull(new (nothrow) ImageDecoder(plugin.release_nonnull()));
|
||||||
|
|
||||||
if (mime_type.has_value()) {
|
|
||||||
if (OwnPtr<ImageDecoderPlugin> plugin = TRY(probe_and_sniff_for_appropriate_plugin_with_known_mime_type(mime_type.value(), bytes)); plugin)
|
|
||||||
return adopt_ref_if_nonnull(new (nothrow) ImageDecoder(plugin.release_nonnull()));
|
|
||||||
}
|
|
||||||
|
|
||||||
return RefPtr<ImageDecoder> {};
|
return RefPtr<ImageDecoder> {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,242 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2022, Tom Needham <06needhamt@gmail.com>
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <AK/MemoryStream.h>
|
|
||||||
#include <AK/Span.h>
|
|
||||||
#include <AK/StdLibExtraDetails.h>
|
|
||||||
#include <AK/String.h>
|
|
||||||
#include <AK/Traits.h>
|
|
||||||
#include <LibGfx/ImageFormats/TGALoader.h>
|
|
||||||
|
|
||||||
namespace Gfx {
|
|
||||||
|
|
||||||
enum TGADataType : u8 {
|
|
||||||
None = 0,
|
|
||||||
UncompressedColorMapped = 1,
|
|
||||||
UncompressedRGB = 2,
|
|
||||||
UncompressedBlackAndWhite = 3,
|
|
||||||
RunLengthEncodedColorMapped = 9,
|
|
||||||
RunLengthEncodedRGB = 10,
|
|
||||||
CompressedBlackAndWhite = 11,
|
|
||||||
CompressedColorMapped = 32,
|
|
||||||
CompressedColorMappedFourPass = 33
|
|
||||||
};
|
|
||||||
|
|
||||||
struct [[gnu::packed]] TGAHeader {
|
|
||||||
u8 id_length;
|
|
||||||
u8 color_map_type;
|
|
||||||
TGADataType data_type_code;
|
|
||||||
i16 color_map_origin;
|
|
||||||
i16 color_map_length;
|
|
||||||
u8 color_map_depth;
|
|
||||||
i16 x_origin;
|
|
||||||
i16 y_origin;
|
|
||||||
u16 width;
|
|
||||||
u16 height;
|
|
||||||
u8 bits_per_pixel;
|
|
||||||
u8 image_descriptor;
|
|
||||||
};
|
|
||||||
static_assert(sizeof(TGAHeader) == 18);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
struct AK::Traits<Gfx::TGAHeader> : public DefaultTraits<Gfx::TGAHeader> {
|
|
||||||
static constexpr bool is_trivially_serializable() { return true; }
|
|
||||||
};
|
|
||||||
|
|
||||||
namespace Gfx {
|
|
||||||
|
|
||||||
struct TGALoadingContext {
|
|
||||||
TGALoadingContext(ReadonlyBytes bytes, FixedMemoryStream stream)
|
|
||||||
: bytes(bytes)
|
|
||||||
, stream(move(stream))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
ReadonlyBytes bytes;
|
|
||||||
FixedMemoryStream stream;
|
|
||||||
TGAHeader header {};
|
|
||||||
RefPtr<Gfx::Bitmap> bitmap;
|
|
||||||
};
|
|
||||||
|
|
||||||
TGAImageDecoderPlugin::TGAImageDecoderPlugin(NonnullOwnPtr<TGALoadingContext> context)
|
|
||||||
: m_context(move(context))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
TGAImageDecoderPlugin::~TGAImageDecoderPlugin() = default;
|
|
||||||
|
|
||||||
IntSize TGAImageDecoderPlugin::size()
|
|
||||||
{
|
|
||||||
return IntSize { m_context->header.width, m_context->header.height };
|
|
||||||
}
|
|
||||||
|
|
||||||
static ErrorOr<void> ensure_header_validity(TGAHeader const& header, size_t whole_image_stream_size)
|
|
||||||
{
|
|
||||||
if ((header.bits_per_pixel % 8) != 0 || header.bits_per_pixel < 8 || header.bits_per_pixel > 32)
|
|
||||||
return Error::from_string_literal("Invalid bit depth");
|
|
||||||
auto bytes_remaining = whole_image_stream_size - sizeof(TGAHeader);
|
|
||||||
if (header.data_type_code == TGADataType::UncompressedRGB && bytes_remaining < static_cast<u64>(header.width) * header.height * (header.bits_per_pixel / 8))
|
|
||||||
return Error::from_string_literal("Not enough data to read an image with the expected size");
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
ErrorOr<void> TGAImageDecoderPlugin::decode_tga_header()
|
|
||||||
{
|
|
||||||
m_context->header = TRY(m_context->stream.read_value<TGAHeader>());
|
|
||||||
TRY(ensure_header_validity(m_context->header, m_context->bytes.size()));
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
bool TGAImageDecoderPlugin::validate_before_create(ReadonlyBytes data)
|
|
||||||
{
|
|
||||||
FixedMemoryStream stream { data };
|
|
||||||
auto header_or_err = stream.read_value<Gfx::TGAHeader>();
|
|
||||||
if (header_or_err.is_error())
|
|
||||||
return false;
|
|
||||||
return !ensure_header_validity(header_or_err.release_value(), data.size()).is_error();
|
|
||||||
}
|
|
||||||
|
|
||||||
ErrorOr<NonnullOwnPtr<ImageDecoderPlugin>> TGAImageDecoderPlugin::create(ReadonlyBytes data)
|
|
||||||
{
|
|
||||||
FixedMemoryStream stream { data };
|
|
||||||
auto context = TRY(adopt_nonnull_own_or_enomem(new (nothrow) TGALoadingContext(data, move(stream))));
|
|
||||||
auto plugin = TRY(adopt_nonnull_own_or_enomem(new (nothrow) TGAImageDecoderPlugin(move(context))));
|
|
||||||
TRY(plugin->decode_tga_header());
|
|
||||||
return plugin;
|
|
||||||
}
|
|
||||||
|
|
||||||
static ErrorOr<ARGB32> read_pixel_from_stream(Stream& stream, size_t bytes_size)
|
|
||||||
{
|
|
||||||
// NOTE: We support 24-bit color pixels and 32-bit color pixels
|
|
||||||
VERIFY(bytes_size == 3 || bytes_size == 4);
|
|
||||||
if (bytes_size == 3) {
|
|
||||||
Array<u8, 3> raw;
|
|
||||||
TRY(stream.read_until_filled(raw.span()));
|
|
||||||
return Color(raw[2], raw[1], raw[0]).value();
|
|
||||||
}
|
|
||||||
return stream.read_value<ARGB32>();
|
|
||||||
}
|
|
||||||
|
|
||||||
struct TGAPixelPacketHeader {
|
|
||||||
bool raw { false };
|
|
||||||
u8 pixels_count { 0 };
|
|
||||||
};
|
|
||||||
|
|
||||||
static ErrorOr<TGAPixelPacketHeader> read_pixel_packet_header(Stream& stream)
|
|
||||||
{
|
|
||||||
auto const pixel_packet_header = TRY(stream.read_value<u8>());
|
|
||||||
bool pixels_raw_in_packet = !(pixel_packet_header & 0x80);
|
|
||||||
u8 pixels_count_in_packet = (pixel_packet_header & 0x7f);
|
|
||||||
// NOTE: Run-length-encoded/Raw pixel packets cannot encode zero pixels,
|
|
||||||
// so value 0 stands for 1 pixel, 1 stands for 2, etc...
|
|
||||||
pixels_count_in_packet++;
|
|
||||||
VERIFY(pixels_count_in_packet > 0);
|
|
||||||
return TGAPixelPacketHeader { pixels_raw_in_packet, pixels_count_in_packet };
|
|
||||||
}
|
|
||||||
|
|
||||||
ErrorOr<ImageFrameDescriptor> TGAImageDecoderPlugin::frame(size_t index, Optional<IntSize>)
|
|
||||||
{
|
|
||||||
auto bits_per_pixel = m_context->header.bits_per_pixel;
|
|
||||||
auto color_map = m_context->header.color_map_type;
|
|
||||||
auto data_type = m_context->header.data_type_code;
|
|
||||||
auto width = m_context->header.width;
|
|
||||||
auto height = m_context->header.height;
|
|
||||||
auto x_origin = m_context->header.x_origin;
|
|
||||||
auto y_origin = m_context->header.y_origin;
|
|
||||||
|
|
||||||
if (index != 0)
|
|
||||||
return Error::from_string_literal("TGAImageDecoderPlugin: frame index must be 0");
|
|
||||||
|
|
||||||
if (color_map > 1)
|
|
||||||
return Error::from_string_literal("TGAImageDecoderPlugin: Invalid color map type");
|
|
||||||
|
|
||||||
if (m_context->bitmap)
|
|
||||||
return ImageFrameDescriptor { m_context->bitmap, 0 };
|
|
||||||
|
|
||||||
RefPtr<Gfx::Bitmap> bitmap;
|
|
||||||
switch (bits_per_pixel) {
|
|
||||||
case 24:
|
|
||||||
bitmap = TRY(Bitmap::create(BitmapFormat::BGRx8888, { m_context->header.width, m_context->header.height }));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 32:
|
|
||||||
bitmap = TRY(Bitmap::create(BitmapFormat::BGRA8888, { m_context->header.width, m_context->header.height }));
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
// FIXME: Implement other TGA bit depths
|
|
||||||
return Error::from_string_literal("TGAImageDecoderPlugin: Can only handle 24 and 32 bits per pixel");
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME: Try to understand the Image origin (instead of X and Y origin coordinates)
|
|
||||||
// based on the Image descriptor, Field 5.6, bits 4 and 5.
|
|
||||||
|
|
||||||
// NOTE: If Y origin is set to a negative number, just assume the generating software
|
|
||||||
// meant that we start with Y origin at the top height of the picture.
|
|
||||||
// At least this is the observed behavior when generating some pictures in GIMP.
|
|
||||||
if (y_origin < 0)
|
|
||||||
y_origin = height;
|
|
||||||
if (y_origin != 0 && y_origin != height)
|
|
||||||
return Error::from_string_literal("TGAImageDecoderPlugin: Can only handle Y origin which is 0 or the entire height");
|
|
||||||
if (x_origin != 0 && x_origin != width)
|
|
||||||
return Error::from_string_literal("TGAImageDecoderPlugin: Can only handle X origin which is 0 or the entire width");
|
|
||||||
|
|
||||||
VERIFY((bits_per_pixel % 8) == 0);
|
|
||||||
auto bytes_per_pixel = bits_per_pixel / 8;
|
|
||||||
|
|
||||||
switch (data_type) {
|
|
||||||
case TGADataType::UncompressedRGB: {
|
|
||||||
for (int row = 0; row < height; ++row) {
|
|
||||||
for (int col = 0; col < width; ++col) {
|
|
||||||
auto actual_row = row;
|
|
||||||
if (y_origin < height)
|
|
||||||
actual_row = height - 1 - row;
|
|
||||||
auto actual_col = col;
|
|
||||||
if (x_origin > width)
|
|
||||||
actual_col = width - 1 - col;
|
|
||||||
bitmap->scanline(actual_row)[actual_col] = TRY(read_pixel_from_stream(m_context->stream, bytes_per_pixel));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case TGADataType::RunLengthEncodedRGB: {
|
|
||||||
size_t pixel_index = 0;
|
|
||||||
size_t pixel_count = height * width;
|
|
||||||
while (pixel_index < pixel_count) {
|
|
||||||
auto pixel_packet_header = TRY(read_pixel_packet_header(m_context->stream));
|
|
||||||
VERIFY(pixel_packet_header.pixels_count > 0);
|
|
||||||
|
|
||||||
auto pixel = TRY(read_pixel_from_stream(m_context->stream, bytes_per_pixel));
|
|
||||||
auto max_pixel_index = min(pixel_index + pixel_packet_header.pixels_count, pixel_count);
|
|
||||||
for (size_t current_pixel_index = pixel_index; current_pixel_index < max_pixel_index; ++current_pixel_index) {
|
|
||||||
int row = current_pixel_index / width;
|
|
||||||
int col = current_pixel_index % width;
|
|
||||||
auto actual_row = row;
|
|
||||||
if (y_origin < height)
|
|
||||||
actual_row = height - 1 - row;
|
|
||||||
auto actual_col = col;
|
|
||||||
if (x_origin > width)
|
|
||||||
actual_col = width - 1 - col;
|
|
||||||
bitmap->scanline(actual_row)[actual_col] = pixel;
|
|
||||||
if (pixel_packet_header.raw && (current_pixel_index + 1) < max_pixel_index)
|
|
||||||
pixel = TRY(read_pixel_from_stream(m_context->stream, bytes_per_pixel));
|
|
||||||
}
|
|
||||||
pixel_index += pixel_packet_header.pixels_count;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
// FIXME: Implement other TGA data types
|
|
||||||
return Error::from_string_literal("TGAImageDecoderPlugin: Can currently only handle the UncompressedRGB or CompressedRGB data type");
|
|
||||||
}
|
|
||||||
|
|
||||||
m_context->bitmap = bitmap;
|
|
||||||
return ImageFrameDescriptor { m_context->bitmap, 0 };
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2022, Tom Needham <06needhamt@gmail.com>
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <LibGfx/ImageFormats/ImageDecoder.h>
|
|
||||||
|
|
||||||
namespace Gfx {
|
|
||||||
|
|
||||||
struct TGALoadingContext;
|
|
||||||
|
|
||||||
class TGAImageDecoderPlugin final : public ImageDecoderPlugin {
|
|
||||||
public:
|
|
||||||
static bool validate_before_create(ReadonlyBytes);
|
|
||||||
static ErrorOr<NonnullOwnPtr<ImageDecoderPlugin>> create(ReadonlyBytes);
|
|
||||||
|
|
||||||
virtual ~TGAImageDecoderPlugin() override;
|
|
||||||
|
|
||||||
virtual IntSize size() override;
|
|
||||||
|
|
||||||
virtual ErrorOr<ImageFrameDescriptor> frame(size_t index, Optional<IntSize> ideal_size = {}) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
TGAImageDecoderPlugin(NonnullOwnPtr<TGALoadingContext>);
|
|
||||||
|
|
||||||
ErrorOr<void> decode_tga_header();
|
|
||||||
NonnullOwnPtr<TGALoadingContext> m_context;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user