Files
ladybird/Libraries/LibGfx/ImageFormats/ImageDecoder.cpp
Zaggy1024 8cacc92ece LibGfx: Allow creation of ColorSpace from YUV CICP
ImageDecoder itself can check the matrix coefficients and range flag
instead. In the future, ImageDecoder should probably convert its images
into RGB color space using the same solution as for video.
2026-04-18 01:25:00 -05:00

85 lines
3.1 KiB
C++

/*
* Copyright (c) 2018-2021, Andreas Kling <andreas@ladybird.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibGfx/ImageFormats/AVIFLoader.h>
#include <LibGfx/ImageFormats/BMPLoader.h>
#include <LibGfx/ImageFormats/GIFLoader.h>
#include <LibGfx/ImageFormats/ICOLoader.h>
#include <LibGfx/ImageFormats/ImageDecoder.h>
#include <LibGfx/ImageFormats/JPEGLoader.h>
#include <LibGfx/ImageFormats/JPEGXLLoader.h>
#include <LibGfx/ImageFormats/PNGLoader.h>
#include <LibGfx/ImageFormats/TIFFLoader.h>
#include <LibGfx/ImageFormats/TinyVGLoader.h>
#include <LibGfx/ImageFormats/WebPLoader.h>
namespace Gfx {
static ErrorOr<OwnPtr<ImageDecoderPlugin>> probe_and_sniff_for_appropriate_plugin(ReadonlyBytes bytes)
{
struct ImagePluginInitializer {
bool (*sniff)(ReadonlyBytes) = nullptr;
ErrorOr<NonnullOwnPtr<ImageDecoderPlugin>> (*create)(ReadonlyBytes) = nullptr;
};
static constexpr ImagePluginInitializer s_initializers[] = {
{ BMPImageDecoderPlugin::sniff, BMPImageDecoderPlugin::create },
{ GIFImageDecoderPlugin::sniff, GIFImageDecoderPlugin::create },
{ ICOImageDecoderPlugin::sniff, ICOImageDecoderPlugin::create },
{ JPEGImageDecoderPlugin::sniff, JPEGImageDecoderPlugin::create },
{ JPEGXLImageDecoderPlugin::sniff, JPEGXLImageDecoderPlugin::create },
{ PNGImageDecoderPlugin::sniff, PNGImageDecoderPlugin::create },
{ TIFFImageDecoderPlugin::sniff, TIFFImageDecoderPlugin::create },
{ TinyVGImageDecoderPlugin::sniff, TinyVGImageDecoderPlugin::create },
{ WebPImageDecoderPlugin::sniff, WebPImageDecoderPlugin::create },
{ AVIFImageDecoderPlugin::sniff, AVIFImageDecoderPlugin::create }
};
for (auto& plugin : s_initializers) {
auto sniff_result = plugin.sniff(bytes);
if (!sniff_result)
continue;
return TRY(plugin.create(bytes));
}
return OwnPtr<ImageDecoderPlugin> {};
}
ErrorOr<ColorSpace> ImageDecoder::color_space()
{
auto maybe_cicp = TRY(m_plugin->cicp());
if (maybe_cicp.has_value()) {
auto cicp = maybe_cicp.release_value();
if (cicp.matrix_coefficients() != Media::MatrixCoefficients::Identity)
return Error::from_string_literal("Unsupported matrix coefficients for CICP");
if (cicp.video_full_range_flag() != Media::VideoFullRangeFlag::Full)
return Error::from_string_literal("Studio range is not supported");
return ColorSpace::from_cicp(cicp);
}
auto maybe_icc_data = TRY(icc_data());
if (!maybe_icc_data.has_value())
return ColorSpace {};
return ColorSpace::load_from_icc_bytes(maybe_icc_data.value());
}
ErrorOr<RefPtr<ImageDecoder>> ImageDecoder::try_create_for_raw_bytes(ReadonlyBytes bytes, [[maybe_unused]] Optional<ByteString> mime_type)
{
if (auto plugin = TRY(probe_and_sniff_for_appropriate_plugin(bytes)); plugin)
return adopt_ref_if_nonnull(new (nothrow) ImageDecoder(plugin.release_nonnull()));
return RefPtr<ImageDecoder> {};
}
ImageDecoder::ImageDecoder(NonnullOwnPtr<ImageDecoderPlugin> plugin)
: m_plugin(move(plugin))
{
}
}