mirror of
https://github.com/RGBCube/serenity
synced 2025-07-26 08:47:34 +00:00
LibGfx: Process colorspace-related chunks in PNGLoader
This stores the data from all these chunks on PNGLoadingContext but doesn't do anything with it yet.
This commit is contained in:
parent
2dc657c77e
commit
53f485c5f0
1 changed files with 115 additions and 0 deletions
|
@ -27,6 +27,31 @@ struct PNG_IHDR {
|
||||||
|
|
||||||
static_assert(AssertSize<PNG_IHDR, 13>());
|
static_assert(AssertSize<PNG_IHDR, 13>());
|
||||||
|
|
||||||
|
struct ChromaticitiesAndWhitepoint {
|
||||||
|
NetworkOrdered<u32> white_point_x;
|
||||||
|
NetworkOrdered<u32> white_point_y;
|
||||||
|
NetworkOrdered<u32> red_x;
|
||||||
|
NetworkOrdered<u32> red_y;
|
||||||
|
NetworkOrdered<u32> green_x;
|
||||||
|
NetworkOrdered<u32> green_y;
|
||||||
|
NetworkOrdered<u32> blue_x;
|
||||||
|
NetworkOrdered<u32> blue_y;
|
||||||
|
};
|
||||||
|
static_assert(AssertSize<ChromaticitiesAndWhitepoint, 32>());
|
||||||
|
|
||||||
|
struct CodingIndependentCodePoints {
|
||||||
|
u8 color_primaries;
|
||||||
|
u8 transfer_function;
|
||||||
|
u8 matrix_coefficients;
|
||||||
|
u8 video_full_range_flag;
|
||||||
|
};
|
||||||
|
static_assert(AssertSize<CodingIndependentCodePoints, 4>());
|
||||||
|
|
||||||
|
struct EmbeddedICCProfile {
|
||||||
|
StringView profile_name;
|
||||||
|
ReadonlyBytes compressed_data;
|
||||||
|
};
|
||||||
|
|
||||||
struct Scanline {
|
struct Scanline {
|
||||||
PNG::FilterType filter;
|
PNG::FilterType filter;
|
||||||
ReadonlyBytes data {};
|
ReadonlyBytes data {};
|
||||||
|
@ -67,6 +92,13 @@ enum PngInterlaceMethod {
|
||||||
Adam7 = 1
|
Adam7 = 1
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum RenderingIntent {
|
||||||
|
Perceptual = 0,
|
||||||
|
RelativeColorimetric = 1,
|
||||||
|
Saturation = 2,
|
||||||
|
AbsoluteColorimetric = 3,
|
||||||
|
};
|
||||||
|
|
||||||
struct PNGLoadingContext {
|
struct PNGLoadingContext {
|
||||||
enum State {
|
enum State {
|
||||||
NotDecoded = 0,
|
NotDecoded = 0,
|
||||||
|
@ -97,6 +129,12 @@ struct PNGLoadingContext {
|
||||||
Vector<PaletteEntry> palette_data;
|
Vector<PaletteEntry> palette_data;
|
||||||
Vector<u8> palette_transparency_data;
|
Vector<u8> palette_transparency_data;
|
||||||
|
|
||||||
|
Optional<ChromaticitiesAndWhitepoint> chromaticities_and_whitepoint;
|
||||||
|
Optional<CodingIndependentCodePoints> coding_independent_code_points;
|
||||||
|
Optional<u32> gamma;
|
||||||
|
Optional<EmbeddedICCProfile> embedded_icc_profile;
|
||||||
|
Optional<RenderingIntent> sRGB_rendering_intent;
|
||||||
|
|
||||||
Checked<int> compute_row_size_for_width(int width)
|
Checked<int> compute_row_size_for_width(int width)
|
||||||
{
|
{
|
||||||
Checked<int> row_size = width;
|
Checked<int> row_size = width;
|
||||||
|
@ -841,6 +879,73 @@ static bool process_tRNS(ReadonlyBytes data, PNGLoadingContext& context)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool process_cHRM(ReadonlyBytes data, PNGLoadingContext& context)
|
||||||
|
{
|
||||||
|
// https://www.w3.org/TR/png/#11cHRM
|
||||||
|
if (data.size() != 32)
|
||||||
|
return false;
|
||||||
|
context.chromaticities_and_whitepoint = *bit_cast<ChromaticitiesAndWhitepoint* const>(data.data());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool process_cICP(ReadonlyBytes data, PNGLoadingContext& context)
|
||||||
|
{
|
||||||
|
// https://www.w3.org/TR/png/#cICP-chunk
|
||||||
|
if (data.size() != 4)
|
||||||
|
return false;
|
||||||
|
context.coding_independent_code_points = *bit_cast<CodingIndependentCodePoints* const>(data.data());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool process_iCCP(ReadonlyBytes data, PNGLoadingContext& context)
|
||||||
|
{
|
||||||
|
// https://www.w3.org/TR/png/#11iCCP
|
||||||
|
size_t profile_name_length_max = min(80u, data.size());
|
||||||
|
size_t profile_name_length = strnlen((char const*)data.data(), profile_name_length_max);
|
||||||
|
if (profile_name_length == 0 || profile_name_length == profile_name_length_max)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (data.size() < profile_name_length + 2)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
u8 compression_method = data[profile_name_length + 1];
|
||||||
|
if (compression_method != 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
context.embedded_icc_profile = EmbeddedICCProfile { { data.data(), profile_name_length }, data.slice(profile_name_length + 2) };
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool process_gAMA(ReadonlyBytes data, PNGLoadingContext& context)
|
||||||
|
{
|
||||||
|
// https://www.w3.org/TR/png/#11gAMA
|
||||||
|
if (data.size() != 4)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
u32 gamma = *bit_cast<NetworkOrdered<u32> const*>(data.data());
|
||||||
|
if (gamma & 0x8000'0000)
|
||||||
|
return false;
|
||||||
|
context.gamma = gamma;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool process_sRGB(ReadonlyBytes data, PNGLoadingContext& context)
|
||||||
|
{
|
||||||
|
// https://www.w3.org/TR/png/#srgb-standard-colour-space
|
||||||
|
if (data.size() != 1)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
u8 rendering_intent = data[0];
|
||||||
|
if (rendering_intent > 3)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
context.sRGB_rendering_intent = (RenderingIntent)rendering_intent;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static bool process_chunk(Streamer& streamer, PNGLoadingContext& context)
|
static bool process_chunk(Streamer& streamer, PNGLoadingContext& context)
|
||||||
{
|
{
|
||||||
u32 chunk_size;
|
u32 chunk_size;
|
||||||
|
@ -872,6 +977,16 @@ static bool process_chunk(Streamer& streamer, PNGLoadingContext& context)
|
||||||
return process_IDAT(chunk_data, context);
|
return process_IDAT(chunk_data, context);
|
||||||
if (!strcmp((char const*)chunk_type, "PLTE"))
|
if (!strcmp((char const*)chunk_type, "PLTE"))
|
||||||
return process_PLTE(chunk_data, context);
|
return process_PLTE(chunk_data, context);
|
||||||
|
if (!strcmp((char const*)chunk_type, "cHRM"))
|
||||||
|
return process_cHRM(chunk_data, context);
|
||||||
|
if (!strcmp((char const*)chunk_type, "cICP"))
|
||||||
|
return process_cICP(chunk_data, context);
|
||||||
|
if (!strcmp((char const*)chunk_type, "iCCP"))
|
||||||
|
return process_iCCP(chunk_data, context);
|
||||||
|
if (!strcmp((char const*)chunk_type, "gAMA"))
|
||||||
|
return process_gAMA(chunk_data, context);
|
||||||
|
if (!strcmp((char const*)chunk_type, "sRGB"))
|
||||||
|
return process_sRGB(chunk_data, context);
|
||||||
if (!strcmp((char const*)chunk_type, "tRNS"))
|
if (!strcmp((char const*)chunk_type, "tRNS"))
|
||||||
return process_tRNS(chunk_data, context);
|
return process_tRNS(chunk_data, context);
|
||||||
return true;
|
return true;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue