mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-21 23:20:20 +00:00
LibGfx+icc: Add ICCProfile support for parametricCurveType and print it
With this, we can parse all types required in v4 "Three-component matrix-based Input profiles".
This commit is contained in:
parent
67f718aa3f
commit
fa00d94e82
Notes:
sideshowbarker
2024-07-17 23:00:03 +09:00
Author: https://github.com/nico Commit: https://github.com/SerenityOS/serenity/commit/fa00d94e82 Pull-request: https://github.com/SerenityOS/serenity/pull/17152
3 changed files with 172 additions and 2 deletions
|
@ -635,6 +635,58 @@ ErrorOr<NonnullRefPtr<MultiLocalizedUnicodeTagData>> MultiLocalizedUnicodeTagDat
|
|||
return adopt_ref(*new MultiLocalizedUnicodeTagData(offset, size, move(records)));
|
||||
}
|
||||
|
||||
unsigned ParametricCurveTagData::parameter_count(FunctionType function_type)
|
||||
{
|
||||
switch (function_type) {
|
||||
case FunctionType::Type0:
|
||||
return 1;
|
||||
case FunctionType::Type1:
|
||||
return 3;
|
||||
case FunctionType::Type2:
|
||||
return 4;
|
||||
case FunctionType::Type3:
|
||||
return 5;
|
||||
case FunctionType::Type4:
|
||||
return 7;
|
||||
}
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
|
||||
ErrorOr<NonnullRefPtr<ParametricCurveTagData>> ParametricCurveTagData::from_bytes(ReadonlyBytes bytes, u32 offset, u32 size)
|
||||
{
|
||||
// ICC v4, 10.18 parametricCurveType
|
||||
VERIFY(tag_type(bytes) == Type);
|
||||
TRY(check_reserved(bytes));
|
||||
|
||||
// "The parametricCurveType describes a one-dimensional curve by specifying one of a predefined set of functions
|
||||
// using the parameters."
|
||||
|
||||
if (bytes.size() < 2 * sizeof(u32) + 2 * sizeof(u16))
|
||||
return Error::from_string_literal("ICC::Profile: parametricCurveType has not enough data");
|
||||
|
||||
u16 raw_function_type = *bit_cast<BigEndian<u16> const*>(bytes.data() + 8);
|
||||
u16 reserved = *bit_cast<BigEndian<u16> const*>(bytes.data() + 10);
|
||||
if (reserved != 0)
|
||||
return Error::from_string_literal("ICC::Profile: parametricCurveType reserved u16 after function type not 0");
|
||||
|
||||
if (raw_function_type > 4)
|
||||
return Error::from_string_literal("ICC::Profile: parametricCurveType unknown function type");
|
||||
|
||||
FunctionType function_type = (FunctionType)raw_function_type;
|
||||
unsigned count = parameter_count(function_type);
|
||||
|
||||
if (bytes.size() < 2 * sizeof(u32) + 2 * sizeof(u16) + count * sizeof(s15Fixed16Number))
|
||||
return Error::from_string_literal("ICC::Profile: parametricCurveType has not enough data for parameters");
|
||||
|
||||
BigEndian<s15Fixed16Number> const* raw_parameters = bit_cast<BigEndian<s15Fixed16Number> const*>(bytes.data() + 12);
|
||||
Array<S15Fixed16, 7> parameters;
|
||||
parameters.fill(0);
|
||||
for (unsigned i = 0; i < count; ++i)
|
||||
parameters[i] = S15Fixed16::create_raw(raw_parameters[i]);
|
||||
|
||||
return adopt_ref(*new ParametricCurveTagData(offset, size, function_type, move(parameters)));
|
||||
}
|
||||
|
||||
ErrorOr<NonnullRefPtr<S15Fixed16ArrayTagData>> S15Fixed16ArrayTagData::from_bytes(ReadonlyBytes bytes, u32 offset, u32 size)
|
||||
{
|
||||
// ICC v4, 10.22 s15Fixed16ArrayType
|
||||
|
@ -897,6 +949,8 @@ ErrorOr<NonnullRefPtr<TagData>> Profile::read_tag(ReadonlyBytes bytes, Detail::T
|
|||
return CurveTagData::from_bytes(tag_bytes, entry.offset_to_beginning_of_tag_data_element, entry.size_of_tag_data_element);
|
||||
case MultiLocalizedUnicodeTagData::Type:
|
||||
return MultiLocalizedUnicodeTagData::from_bytes(tag_bytes, entry.offset_to_beginning_of_tag_data_element, entry.size_of_tag_data_element);
|
||||
case ParametricCurveTagData::Type:
|
||||
return ParametricCurveTagData::from_bytes(tag_bytes, entry.offset_to_beginning_of_tag_data_element, entry.size_of_tag_data_element);
|
||||
case S15Fixed16ArrayTagData::Type:
|
||||
return S15Fixed16ArrayTagData::from_bytes(tag_bytes, entry.offset_to_beginning_of_tag_data_element, entry.size_of_tag_data_element);
|
||||
case TextDescriptionTagData::Type:
|
||||
|
|
|
@ -224,6 +224,8 @@ private:
|
|||
u64 m_bits = 0;
|
||||
};
|
||||
|
||||
using S15Fixed16 = FixedPoint<16, i32>;
|
||||
|
||||
struct XYZ {
|
||||
double x { 0 };
|
||||
double y { 0 };
|
||||
|
@ -313,13 +315,100 @@ private:
|
|||
Vector<Record> m_records;
|
||||
};
|
||||
|
||||
// ICC v4, 10.18 parametricCurveType
|
||||
class ParametricCurveTagData : public TagData {
|
||||
public:
|
||||
// Table 68 — parametricCurveType function type encoding
|
||||
enum class FunctionType {
|
||||
// Y = X**g
|
||||
Type0,
|
||||
|
||||
// Y = (a*X + b)**g if X >= -b/a
|
||||
// = 0 else
|
||||
Type1,
|
||||
CIE_122_1966 = Type1,
|
||||
|
||||
// Y = (a*X + b)**g + c if X >= -b/a
|
||||
// = c else
|
||||
Type2,
|
||||
IEC_61966_1 = Type2,
|
||||
|
||||
// Y = (a*X + b)**g if X >= d
|
||||
// = c*X else
|
||||
Type3,
|
||||
IEC_61966_2_1 = Type3,
|
||||
sRGB = Type3,
|
||||
|
||||
// Y = (a*X + b)**g + e if X >= d
|
||||
// = c*X + f else
|
||||
Type4,
|
||||
};
|
||||
|
||||
// "The domain and range of each function shall be [0,0 1,0]. Any function value outside the range shall be clipped
|
||||
// to the range of the function."
|
||||
// "NOTE 1 The parameters selected for a parametric curve can result in complex or undefined values for the input range
|
||||
// used. This can occur, for example, if d < -b/a. In such cases the behaviour of the curve is undefined."
|
||||
|
||||
static constexpr TagTypeSignature Type { 0x70617261 }; // 'para'
|
||||
|
||||
static ErrorOr<NonnullRefPtr<ParametricCurveTagData>> from_bytes(ReadonlyBytes, u32 offset, u32 size);
|
||||
|
||||
ParametricCurveTagData(u32 offset, u32 size, FunctionType function_type, Array<S15Fixed16, 7> parameters)
|
||||
: TagData(offset, size, Type)
|
||||
, m_function_type(function_type)
|
||||
, m_parameters(move(parameters))
|
||||
{
|
||||
}
|
||||
|
||||
FunctionType function_type() const { return m_function_type; }
|
||||
|
||||
static unsigned parameter_count(FunctionType);
|
||||
|
||||
S15Fixed16 g() const { return m_parameters[0]; }
|
||||
S15Fixed16 a() const
|
||||
{
|
||||
VERIFY(function_type() >= FunctionType::Type1);
|
||||
return m_parameters[1];
|
||||
}
|
||||
S15Fixed16 b() const
|
||||
{
|
||||
VERIFY(function_type() >= FunctionType::Type1);
|
||||
return m_parameters[2];
|
||||
}
|
||||
S15Fixed16 c() const
|
||||
{
|
||||
VERIFY(function_type() >= FunctionType::Type2);
|
||||
return m_parameters[3];
|
||||
}
|
||||
S15Fixed16 d() const
|
||||
{
|
||||
VERIFY(function_type() >= FunctionType::Type3);
|
||||
return m_parameters[4];
|
||||
}
|
||||
S15Fixed16 e() const
|
||||
{
|
||||
VERIFY(function_type() >= FunctionType::Type4);
|
||||
return m_parameters[5];
|
||||
}
|
||||
S15Fixed16 f() const
|
||||
{
|
||||
VERIFY(function_type() >= FunctionType::Type4);
|
||||
return m_parameters[6];
|
||||
}
|
||||
|
||||
private:
|
||||
FunctionType m_function_type;
|
||||
|
||||
// Contains, in this order, g a b c d e f.
|
||||
// Not all FunctionTypes use all parameters.
|
||||
Array<S15Fixed16, 7> m_parameters;
|
||||
};
|
||||
|
||||
// ICC v4, 10.22 s15Fixed16ArrayType
|
||||
class S15Fixed16ArrayTagData : public TagData {
|
||||
public:
|
||||
static constexpr TagTypeSignature Type { 0x73663332 }; // 'sf32'
|
||||
|
||||
using S15Fixed16 = FixedPoint<16, i32>;
|
||||
|
||||
static ErrorOr<NonnullRefPtr<S15Fixed16ArrayTagData>> from_bytes(ReadonlyBytes, u32 offset, u32 size);
|
||||
|
||||
S15Fixed16ArrayTagData(u32 offset, u32 size, Vector<S15Fixed16, 9> values)
|
||||
|
|
|
@ -112,6 +112,33 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
|
|||
record.iso_3166_1_country_code >> 8, record.iso_3166_1_country_code & 0xff,
|
||||
record.text);
|
||||
}
|
||||
} else if (tag_data->type() == Gfx::ICC::ParametricCurveTagData::Type) {
|
||||
auto& parametric_curve = static_cast<Gfx::ICC::ParametricCurveTagData&>(*tag_data);
|
||||
switch (parametric_curve.function_type()) {
|
||||
case Gfx::ICC::ParametricCurveTagData::FunctionType::Type0:
|
||||
outln(" Y = X**{}", parametric_curve.g());
|
||||
break;
|
||||
case Gfx::ICC::ParametricCurveTagData::FunctionType::Type1:
|
||||
outln(" Y = ({}*X + {})**{} if X >= -{}/{}",
|
||||
parametric_curve.a(), parametric_curve.b(), parametric_curve.g(), parametric_curve.b(), parametric_curve.a());
|
||||
outln(" Y = 0 else");
|
||||
break;
|
||||
case Gfx::ICC::ParametricCurveTagData::FunctionType::Type2:
|
||||
outln(" Y = ({}*X + {})**{} + {} if X >= -{}/{}",
|
||||
parametric_curve.a(), parametric_curve.b(), parametric_curve.g(), parametric_curve.c(), parametric_curve.b(), parametric_curve.a());
|
||||
outln(" Y = {} else", parametric_curve.c());
|
||||
break;
|
||||
case Gfx::ICC::ParametricCurveTagData::FunctionType::Type3:
|
||||
outln(" Y = ({}*X + {})**{} if X >= {}",
|
||||
parametric_curve.a(), parametric_curve.b(), parametric_curve.g(), parametric_curve.d());
|
||||
outln(" Y = {}*X else", parametric_curve.c());
|
||||
break;
|
||||
case Gfx::ICC::ParametricCurveTagData::FunctionType::Type4:
|
||||
outln(" Y = ({}*X + {})**{} + {} if X >= {}",
|
||||
parametric_curve.a(), parametric_curve.b(), parametric_curve.g(), parametric_curve.e(), parametric_curve.d());
|
||||
outln(" Y = {}*X + {} else", parametric_curve.c(), parametric_curve.f());
|
||||
break;
|
||||
}
|
||||
} else if (tag_data->type() == Gfx::ICC::S15Fixed16ArrayTagData::Type) {
|
||||
// This tag can contain arbitrarily many fixed-point numbers, but in practice it's
|
||||
// exclusively used for the 'chad' tag, where it always contains 9 values that
|
||||
|
|
Loading…
Reference in a new issue