LibGfx: Integrate JPEG decoder with rest of the system

This patch adds functions like `load_jpeg` to JPGLoader to make the
JPEG decoder conform to the API that bitmap loader uses :^)
This commit is contained in:
devashish 2020-06-22 12:33:56 +05:30 committed by Andreas Kling
parent 8b71b839fa
commit a8b00780a8
5 changed files with 55 additions and 30 deletions

View file

@ -32,6 +32,7 @@
#include <LibGfx/Bitmap.h>
#include <LibGfx/GIFLoader.h>
#include <LibGfx/ICOLoader.h>
#include <LibGfx/JPGLoader.h>
#include <LibGfx/PBMLoader.h>
#include <LibGfx/PNGLoader.h>
#include <LibGfx/PPMLoader.h>

View file

@ -39,7 +39,9 @@
__ENUMERATE_IMAGE_FORMAT(ppm, ".ppm") \
__ENUMERATE_IMAGE_FORMAT(gif, ".gif") \
__ENUMERATE_IMAGE_FORMAT(bmp, ".bmp") \
__ENUMERATE_IMAGE_FORMAT(ico, ".ico")
__ENUMERATE_IMAGE_FORMAT(ico, ".ico") \
__ENUMERATE_IMAGE_FORMAT(jpg, ".jpg") \
__ENUMERATE_IMAGE_FORMAT(jpg, ".jpeg")
namespace Gfx {

View file

@ -66,7 +66,6 @@ ImageDecoder::ImageDecoder(const u8* data, size_t size)
return;
m_plugin = nullptr;
return;
}
ImageDecoder::~ImageDecoder()

View file

@ -329,7 +329,7 @@ static bool read_start_of_scan(BufferStream& stream, JPGLoadingContext& context)
if (stream.handle_read_failure())
return false;
bytes_to_read -= 2;
if (!bounds_okay(stream.offset(), bytes_to_read, context.compressed_size))
if (!bounds_okay(stream.offset(), bytes_to_read, context.data_size))
return false;
u8 component_count;
stream >> component_count;
@ -395,7 +395,7 @@ static bool read_reset_marker(BufferStream& stream, JPGLoadingContext& context)
static bool read_huffman_table(BufferStream& stream, JPGLoadingContext& context)
{
i32 bytes_to_read = read_be_word(stream);
if (!bounds_okay(stream.offset(), bytes_to_read, context.compressed_size))
if (!bounds_okay(stream.offset(), bytes_to_read, context.data_size))
return false;
bytes_to_read -= 2;
while (bytes_to_read > 0) {
@ -485,7 +485,7 @@ static bool read_start_of_frame(BufferStream& stream, JPGLoadingContext& context
return false;
bytes_to_read -= 2;
if (!bounds_okay(stream.offset(), bytes_to_read, context.compressed_size))
if (!bounds_okay(stream.offset(), bytes_to_read, context.data_size))
return false;
stream >> context.frame.precision;
@ -555,7 +555,7 @@ static bool read_quantization_table(BufferStream& stream, JPGLoadingContext& con
if (stream.handle_read_failure())
return false;
bytes_to_read -= 2;
if (!bounds_okay(stream.offset(), bytes_to_read, context.compressed_size))
if (!bounds_okay(stream.offset(), bytes_to_read, context.data_size))
return false;
while (bytes_to_read > 0) {
u8 info_byte;
@ -935,9 +935,9 @@ static bool scan_huffman_stream(BufferStream& stream, JPGLoadingContext& context
ASSERT_NOT_REACHED();
}
static bool load_jpg_impl(JPGLoadingContext& context)
static bool decode_jpg(JPGLoadingContext& context)
{
ByteBuffer buffer = ByteBuffer::wrap(context.compressed_data, context.compressed_size);
ByteBuffer buffer = ByteBuffer::wrap(context.data, context.data_size);
BufferStream stream(buffer);
if (!parse_header(stream, context))
return false;
@ -959,11 +959,44 @@ static bool load_jpg_impl(JPGLoadingContext& context)
return true;
}
static RefPtr<Gfx::Bitmap> load_jpg_impl(const u8* data, size_t data_size)
{
JPGLoadingContext context;
context.data = data;
context.data_size = data_size;
if (!decode_jpg(context))
return nullptr;
return context.bitmap;
}
RefPtr<Gfx::Bitmap> load_jpg(const StringView& path)
{
MappedFile mapped_file(path);
if (!mapped_file.is_valid()) {
return nullptr;
}
auto bitmap = load_jpg_impl((const u8*)mapped_file.data(), mapped_file.size());
if (bitmap)
bitmap->set_mmap_name(String::format("Gfx::Bitmap [%dx%d] - Decoded JPG: %s", bitmap->width(), bitmap->height(), LexicalPath::canonicalized_path(path).characters()));
return bitmap;
}
RefPtr<Gfx::Bitmap> load_jpg_from_memory(const u8* data, size_t length)
{
auto bitmap = load_jpg_impl(data, length);
if (bitmap)
bitmap->set_mmap_name(String::format("Gfx::Bitmap [%dx%d] - Decoded jpg: <memory>", bitmap->width(), bitmap->height()));
return bitmap;
}
JPGImageDecoderPlugin::JPGImageDecoderPlugin(const u8* data, size_t size)
{
m_context = make<JPGLoadingContext>();
m_context->compressed_data = data;
m_context->compressed_size = size;
m_context->data = data;
m_context->data_size = size;
m_context->huffman_stream.stream.ensure_capacity(50 * KB);
}
@ -986,7 +1019,7 @@ RefPtr<Gfx::Bitmap> JPGImageDecoderPlugin::bitmap()
if (m_context->state == JPGLoadingContext::State::Error)
return nullptr;
if (m_context->state < JPGLoadingContext::State::BitmapDecoded) {
if (!load_jpg_impl(*m_context)) {
if (!decode_jpg(*m_context)) {
m_context->state = JPGLoadingContext::State::Error;
return nullptr;
}
@ -1011,10 +1044,10 @@ bool JPGImageDecoderPlugin::set_nonvolatile()
bool JPGImageDecoderPlugin::sniff()
{
return m_context->compressed_size > 3
&& m_context->compressed_data[0] == 0xFF
&& m_context->compressed_data[1] == 0xD8
&& m_context->compressed_data[2] == 0xFF;
return m_context->data_size > 3
&& m_context->data[0] == 0xFF
&& m_context->data[1] == 0xD8
&& m_context->data[2] == 0xFF;
}
bool JPGImageDecoderPlugin::is_animated()
@ -1039,17 +1072,4 @@ ImageFrameDescriptor JPGImageDecoderPlugin::frame(size_t i)
}
return {};
}
RefPtr<Gfx::Bitmap> load_jpg(const StringView& path)
{
MappedFile mapped_file(path);
if (!mapped_file.is_valid())
return nullptr;
JPGImageDecoderPlugin jpg_decoder((const u8*)mapped_file.data(), mapped_file.size());
auto bitmap = jpg_decoder.bitmap();
if (bitmap)
bitmap->set_mmap_name(String::format("Gfx::Bitmap [%dx%d] - Decoded JPG: %s",
bitmap->width(), bitmap->height(), LexicalPath::canonicalized_path(path).characters()));
return bitmap;
}
}

View file

@ -87,6 +87,9 @@
namespace Gfx {
RefPtr<Gfx::Bitmap> load_jpg(const StringView& path);
RefPtr<Gfx::Bitmap> load_jpg_from_memory(const u8* data, size_t length);
/**
* MCU means group of data units that are coded together. A data unit is an 8x8
* block of component data. In interleaved scans, number of non-interleaved data
@ -165,8 +168,8 @@ struct JPGLoadingContext {
};
State state { State::NotDecoded };
const u8* compressed_data { nullptr };
size_t compressed_size { 0 };
const u8* data { nullptr };
size_t data_size { 0 };
u32 luma_table[64];
u32 chroma_table[64];
StartOfFrame frame;