mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-08-27 04:37:22 +00:00
Everywhere: Hoist the Libraries folder to the top-level
This commit is contained in:
parent
950e819ee7
commit
93712b24bf
Notes:
github-actions[bot]
2024-11-10 11:51:52 +00:00
Author: https://github.com/trflynn89
Commit: 93712b24bf
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/2256
Reviewed-by: https://github.com/sideshowbarker
4547 changed files with 104 additions and 113 deletions
227
Libraries/LibGfx/ImageFormats/JPEGLoader.cpp
Normal file
227
Libraries/LibGfx/ImageFormats/JPEGLoader.cpp
Normal file
|
@ -0,0 +1,227 @@
|
|||
/*
|
||||
* Copyright (c) 2024, Andreas Kling <andreas@ladybird.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <LibGfx/CMYKBitmap.h>
|
||||
#include <LibGfx/ImageFormats/JPEGLoader.h>
|
||||
#include <jpeglib.h>
|
||||
#include <setjmp.h>
|
||||
|
||||
namespace Gfx {
|
||||
|
||||
struct JPEGLoadingContext {
|
||||
enum class State {
|
||||
NotDecoded,
|
||||
Error,
|
||||
Decoded,
|
||||
};
|
||||
|
||||
State state { State::NotDecoded };
|
||||
|
||||
RefPtr<Gfx::Bitmap> rgb_bitmap;
|
||||
RefPtr<Gfx::CMYKBitmap> cmyk_bitmap;
|
||||
|
||||
ReadonlyBytes data;
|
||||
Vector<u8> icc_data;
|
||||
|
||||
JPEGLoadingContext(ReadonlyBytes data)
|
||||
: data(data)
|
||||
{
|
||||
}
|
||||
|
||||
ErrorOr<void> decode();
|
||||
};
|
||||
|
||||
struct JPEGErrorManager : jpeg_error_mgr {
|
||||
jmp_buf setjmp_buffer {};
|
||||
};
|
||||
|
||||
ErrorOr<void> JPEGLoadingContext::decode()
|
||||
{
|
||||
struct jpeg_decompress_struct cinfo;
|
||||
struct JPEGErrorManager jerr;
|
||||
cinfo.err = jpeg_std_error(&jerr);
|
||||
|
||||
jpeg_source_mgr source_manager {};
|
||||
|
||||
if (setjmp(jerr.setjmp_buffer)) {
|
||||
jpeg_destroy_decompress(&cinfo);
|
||||
state = State::Error;
|
||||
return Error::from_string_literal("Failed to decode JPEG");
|
||||
}
|
||||
|
||||
jerr.error_exit = [](j_common_ptr cinfo) {
|
||||
char buffer[JMSG_LENGTH_MAX];
|
||||
(*cinfo->err->format_message)(cinfo, buffer);
|
||||
dbgln("JPEG error: {}", buffer);
|
||||
longjmp(static_cast<JPEGErrorManager*>(cinfo->err)->setjmp_buffer, 1);
|
||||
};
|
||||
jpeg_create_decompress(&cinfo);
|
||||
|
||||
source_manager.next_input_byte = data.data();
|
||||
source_manager.bytes_in_buffer = data.size();
|
||||
source_manager.init_source = [](j_decompress_ptr) {};
|
||||
source_manager.fill_input_buffer = [](j_decompress_ptr) -> boolean { return false; };
|
||||
source_manager.skip_input_data = [](j_decompress_ptr context, long num_bytes) {
|
||||
if (num_bytes > static_cast<long>(context->src->bytes_in_buffer)) {
|
||||
context->src->bytes_in_buffer = 0;
|
||||
return;
|
||||
}
|
||||
context->src->next_input_byte += num_bytes;
|
||||
context->src->bytes_in_buffer -= num_bytes;
|
||||
};
|
||||
source_manager.resync_to_restart = jpeg_resync_to_restart;
|
||||
source_manager.term_source = [](j_decompress_ptr) {};
|
||||
|
||||
cinfo.src = &source_manager;
|
||||
|
||||
jpeg_save_markers(&cinfo, JPEG_APP0 + 2, 0xFFFF);
|
||||
if (jpeg_read_header(&cinfo, TRUE) != JPEG_HEADER_OK) {
|
||||
jpeg_destroy_decompress(&cinfo);
|
||||
return Error::from_string_literal("Failed to read JPEG header");
|
||||
}
|
||||
|
||||
if (cinfo.jpeg_color_space == JCS_CMYK || cinfo.jpeg_color_space == JCS_YCCK) {
|
||||
cinfo.out_color_space = JCS_CMYK;
|
||||
} else {
|
||||
cinfo.out_color_space = JCS_EXT_BGRX;
|
||||
}
|
||||
|
||||
jpeg_start_decompress(&cinfo);
|
||||
bool could_read_all_scanlines = true;
|
||||
|
||||
if (cinfo.out_color_space == JCS_EXT_BGRX) {
|
||||
rgb_bitmap = TRY(Gfx::Bitmap::create(Gfx::BitmapFormat::BGRx8888, { static_cast<int>(cinfo.output_width), static_cast<int>(cinfo.output_height) }));
|
||||
while (cinfo.output_scanline < cinfo.output_height) {
|
||||
auto* row_ptr = (u8*)rgb_bitmap->scanline(cinfo.output_scanline);
|
||||
auto out_size = jpeg_read_scanlines(&cinfo, &row_ptr, 1);
|
||||
if (cinfo.output_scanline < cinfo.output_height && out_size == 0) {
|
||||
dbgln("JPEG Warning: Decoding produced no more scanlines in scanline {}/{}.", cinfo.output_scanline, cinfo.output_height);
|
||||
could_read_all_scanlines = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
cmyk_bitmap = TRY(CMYKBitmap::create_with_size({ static_cast<int>(cinfo.output_width), static_cast<int>(cinfo.output_height) }));
|
||||
while (cinfo.output_scanline < cinfo.output_height) {
|
||||
auto* row_ptr = (u8*)cmyk_bitmap->scanline(cinfo.output_scanline);
|
||||
auto out_size = jpeg_read_scanlines(&cinfo, &row_ptr, 1);
|
||||
if (cinfo.output_scanline < cinfo.output_height && out_size == 0) {
|
||||
dbgln("JPEG Warning: Decoding produced no more scanlines in scanline {}/{}.", cinfo.output_scanline, cinfo.output_height);
|
||||
could_read_all_scanlines = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
JOCTET* icc_data_ptr = nullptr;
|
||||
unsigned int icc_data_length = 0;
|
||||
if (jpeg_read_icc_profile(&cinfo, &icc_data_ptr, &icc_data_length)) {
|
||||
icc_data.resize(icc_data_length);
|
||||
memcpy(icc_data.data(), icc_data_ptr, icc_data_length);
|
||||
free(icc_data_ptr);
|
||||
}
|
||||
|
||||
if (could_read_all_scanlines)
|
||||
jpeg_finish_decompress(&cinfo);
|
||||
else
|
||||
jpeg_abort_decompress(&cinfo);
|
||||
jpeg_destroy_decompress(&cinfo);
|
||||
|
||||
if (cmyk_bitmap && !rgb_bitmap)
|
||||
rgb_bitmap = TRY(cmyk_bitmap->to_low_quality_rgb());
|
||||
|
||||
state = State::Decoded;
|
||||
return {};
|
||||
}
|
||||
|
||||
JPEGImageDecoderPlugin::JPEGImageDecoderPlugin(NonnullOwnPtr<JPEGLoadingContext> context)
|
||||
: m_context(move(context))
|
||||
{
|
||||
}
|
||||
|
||||
JPEGImageDecoderPlugin::~JPEGImageDecoderPlugin() = default;
|
||||
|
||||
IntSize JPEGImageDecoderPlugin::size()
|
||||
{
|
||||
if (m_context->state == JPEGLoadingContext::State::NotDecoded)
|
||||
(void)frame(0);
|
||||
|
||||
if (m_context->state == JPEGLoadingContext::State::Error)
|
||||
return {};
|
||||
if (m_context->rgb_bitmap)
|
||||
return m_context->rgb_bitmap->size();
|
||||
if (m_context->cmyk_bitmap)
|
||||
return m_context->cmyk_bitmap->size();
|
||||
return {};
|
||||
}
|
||||
|
||||
bool JPEGImageDecoderPlugin::sniff(ReadonlyBytes data)
|
||||
{
|
||||
return data.size() > 3
|
||||
&& data.data()[0] == 0xFF
|
||||
&& data.data()[1] == 0xD8
|
||||
&& data.data()[2] == 0xFF;
|
||||
}
|
||||
|
||||
ErrorOr<NonnullOwnPtr<ImageDecoderPlugin>> JPEGImageDecoderPlugin::create(ReadonlyBytes data)
|
||||
{
|
||||
return adopt_own(*new JPEGImageDecoderPlugin(make<JPEGLoadingContext>(data)));
|
||||
}
|
||||
|
||||
ErrorOr<ImageFrameDescriptor> JPEGImageDecoderPlugin::frame(size_t index, Optional<IntSize>)
|
||||
{
|
||||
if (index > 0)
|
||||
return Error::from_string_literal("JPEGImageDecoderPlugin: Invalid frame index");
|
||||
|
||||
if (m_context->state == JPEGLoadingContext::State::Error)
|
||||
return Error::from_string_literal("JPEGImageDecoderPlugin: Decoding failed");
|
||||
|
||||
if (m_context->state < JPEGLoadingContext::State::Decoded) {
|
||||
TRY(m_context->decode());
|
||||
m_context->state = JPEGLoadingContext::State::Decoded;
|
||||
}
|
||||
|
||||
return ImageFrameDescriptor { m_context->rgb_bitmap, 0 };
|
||||
}
|
||||
|
||||
Optional<Metadata const&> JPEGImageDecoderPlugin::metadata()
|
||||
{
|
||||
return OptionalNone {};
|
||||
}
|
||||
|
||||
ErrorOr<Optional<ReadonlyBytes>> JPEGImageDecoderPlugin::icc_data()
|
||||
{
|
||||
if (m_context->state == JPEGLoadingContext::State::NotDecoded)
|
||||
(void)frame(0);
|
||||
|
||||
if (!m_context->icc_data.is_empty())
|
||||
return m_context->icc_data;
|
||||
return OptionalNone {};
|
||||
}
|
||||
|
||||
NaturalFrameFormat JPEGImageDecoderPlugin::natural_frame_format() const
|
||||
{
|
||||
if (m_context->state == JPEGLoadingContext::State::NotDecoded)
|
||||
(void)const_cast<JPEGImageDecoderPlugin&>(*this).frame(0);
|
||||
|
||||
if (m_context->cmyk_bitmap)
|
||||
return NaturalFrameFormat::CMYK;
|
||||
return NaturalFrameFormat::RGB;
|
||||
}
|
||||
|
||||
ErrorOr<NonnullRefPtr<CMYKBitmap>> JPEGImageDecoderPlugin::cmyk_frame()
|
||||
{
|
||||
if (m_context->state == JPEGLoadingContext::State::NotDecoded)
|
||||
(void)frame(0);
|
||||
|
||||
if (m_context->state == JPEGLoadingContext::State::Error)
|
||||
return Error::from_string_literal("JPEGImageDecoderPlugin: Decoding failed");
|
||||
if (!m_context->cmyk_bitmap)
|
||||
return Error::from_string_literal("JPEGImageDecoderPlugin: No CMYK data available");
|
||||
return *m_context->cmyk_bitmap;
|
||||
}
|
||||
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue