Roll skcms from b9593d4e39ea to 4e8691e28194 (1 revision)
https://skia.googlesource.com/skcms.git/+log/b9593d4e39ea..4e8691e28194 2021-03-31 mtklein@google.com B2A part 1, types and parsing If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/skcms-skia-autoroll Please CC mtklein@google.com on the revert to ensure that a human is aware of the problem. To report a problem with the AutoRoller itself, please file a bug: https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/master/autoroll/README.md Cq-Include-Trybots: luci.chromium.try:linux-blink-rel Tbr: mtklein@google.com Change-Id: I52d7f3b5ca56be4bb6c8a4955b70dc09bf63ad96 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/391159 Reviewed-by: skia-autoroll <skia-autoroll@skia-public.iam.gserviceaccount.com> Commit-Queue: skia-autoroll <skia-autoroll@skia-public.iam.gserviceaccount.com>
This commit is contained in:
parent
759bbf7b60
commit
94dc3b709b
40
include/third_party/skcms/skcms.h
vendored
40
include/third_party/skcms/skcms.h
vendored
@ -104,8 +104,12 @@ typedef union skcms_Curve {
|
||||
};
|
||||
} skcms_Curve;
|
||||
|
||||
// Complex transforms between device space (A) and profile connection space (B):
|
||||
// A2B: device -> [ "A" curves -> CLUT ] -> [ "M" curves -> matrix ] -> "B" curves -> PCS
|
||||
// B2A: device <- [ "A" curves <- CLUT ] <- [ "M" curves <- matrix ] <- "B" curves <- PCS
|
||||
|
||||
typedef struct skcms_A2B {
|
||||
// Optional: N 1D curves, followed by an N-dimensional CLUT.
|
||||
// Optional: N 1D "A" curves, followed by an N-dimensional CLUT.
|
||||
// If input_channels == 0, these curves and CLUT are skipped,
|
||||
// Otherwise, input_channels must be in [1, 4].
|
||||
uint32_t input_channels;
|
||||
@ -114,18 +118,41 @@ typedef struct skcms_A2B {
|
||||
const uint8_t* grid_8;
|
||||
const uint8_t* grid_16;
|
||||
|
||||
// Optional: 3 1D curves, followed by a color matrix.
|
||||
// Optional: 3 1D "M" curves, followed by a color matrix.
|
||||
// If matrix_channels == 0, these curves and matrix are skipped,
|
||||
// Otherwise, matrix_channels must be 3.
|
||||
uint32_t matrix_channels;
|
||||
skcms_Curve matrix_curves[3];
|
||||
skcms_Matrix3x4 matrix;
|
||||
|
||||
// Required: 3 1D curves. Always present, and output_channels must be 3.
|
||||
// Required: 3 1D "B" curves. Always present, and output_channels must be 3.
|
||||
uint32_t output_channels;
|
||||
skcms_Curve output_curves[3];
|
||||
} skcms_A2B;
|
||||
|
||||
typedef struct skcms_B2A {
|
||||
// Required: 3 1D "B" curves. Always present, and input_channels must be 3.
|
||||
uint32_t input_channels;
|
||||
skcms_Curve input_curves[3];
|
||||
|
||||
// Optional: a color matrix, followed by 3 1D "M" curves.
|
||||
// If matrix_channels == 0, this matrix and these curves are skipped,
|
||||
// Otherwise, matrix_channels must be 3.
|
||||
uint32_t matrix_channels;
|
||||
skcms_Matrix3x4 matrix;
|
||||
skcms_Curve matrix_curves[3];
|
||||
|
||||
// Optional: an N-dimensional CLUT, followed by N 1D "A" curves.
|
||||
// If output_channels == 0, this CLUT and these curves are skipped,
|
||||
// Otherwise, output_channels must be in [1, 4].
|
||||
uint32_t output_channels;
|
||||
uint8_t grid_points[4];
|
||||
const uint8_t* grid_8;
|
||||
const uint8_t* grid_16;
|
||||
skcms_Curve output_curves[4];
|
||||
} skcms_B2A;
|
||||
|
||||
|
||||
typedef struct skcms_ICCProfile {
|
||||
const uint8_t* buffer;
|
||||
|
||||
@ -151,6 +178,13 @@ typedef struct skcms_ICCProfile {
|
||||
// same following any user-provided prioritization of A2B0, A2B1, or A2B2.
|
||||
bool has_A2B;
|
||||
skcms_A2B A2B;
|
||||
|
||||
// If the profile has a valid B2A0 or B2A1 tag, skcms_Parse() sets B2A to
|
||||
// that data, and has_B2A to true. skcms_ParseWithA2BPriority() does the
|
||||
// same following any user-provided prioritization of B2A0, B2A1, or B2A2.
|
||||
bool has_B2A;
|
||||
skcms_B2A B2A;
|
||||
|
||||
} skcms_ICCProfile;
|
||||
|
||||
// The sRGB color profile is so commonly used that we offer a canonical skcms_ICCProfile for it.
|
||||
|
437
third_party/skcms/skcms.cc
vendored
437
third_party/skcms/skcms.cc
vendored
@ -288,8 +288,7 @@ enum {
|
||||
skcms_Signature_bXYZ = 0x6258595A,
|
||||
|
||||
skcms_Signature_A2B0 = 0x41324230,
|
||||
skcms_Signature_A2B1 = 0x41324231,
|
||||
skcms_Signature_mAB = 0x6D414220,
|
||||
skcms_Signature_B2A0 = 0x42324130,
|
||||
|
||||
skcms_Signature_CHAD = 0x63686164,
|
||||
skcms_Signature_WTPT = 0x77747074,
|
||||
@ -298,6 +297,8 @@ enum {
|
||||
skcms_Signature_curv = 0x63757276,
|
||||
skcms_Signature_mft1 = 0x6D667431,
|
||||
skcms_Signature_mft2 = 0x6D667432,
|
||||
skcms_Signature_mAB = 0x6D414220,
|
||||
skcms_Signature_mBA = 0x6D424120,
|
||||
skcms_Signature_para = 0x70617261,
|
||||
skcms_Signature_sf32 = 0x73663332,
|
||||
// XYZ is also a PCS signature, so it's defined in skcms.h
|
||||
@ -606,9 +607,17 @@ static bool read_mft_common(const mft_CommonLayout* mftTag, skcms_A2B* a2b) {
|
||||
// field/flag.
|
||||
a2b->matrix_channels = 0;
|
||||
|
||||
a2b->input_channels = mftTag->input_channels[0];
|
||||
a2b-> input_channels = mftTag-> input_channels[0];
|
||||
a2b->output_channels = mftTag->output_channels[0];
|
||||
|
||||
for (uint32_t i = 0; i < a2b->input_channels; ++i) {
|
||||
a2b->grid_points[i] = mftTag->grid_points[0];
|
||||
}
|
||||
// The grid only makes sense with at least two points along each axis
|
||||
if (a2b->grid_points[0] < 2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// We require exactly three (ie XYZ/Lab/RGB) output channels
|
||||
if (a2b->output_channels != ARRAY_COUNT(a2b->output_curves)) {
|
||||
return false;
|
||||
@ -618,95 +627,116 @@ static bool read_mft_common(const mft_CommonLayout* mftTag, skcms_A2B* a2b) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < a2b->input_channels; ++i) {
|
||||
a2b->grid_points[i] = mftTag->grid_points[0];
|
||||
return true;
|
||||
}
|
||||
|
||||
// All as the A2B version above, except where noted.
|
||||
static bool read_mft_common(const mft_CommonLayout* mftTag, skcms_B2A* b2a) {
|
||||
// All the same as A2B until the next comment...
|
||||
b2a->matrix_channels = 0;
|
||||
|
||||
b2a-> input_channels = mftTag-> input_channels[0];
|
||||
b2a->output_channels = mftTag->output_channels[0];
|
||||
|
||||
for (uint32_t i = 0; i < b2a->input_channels; ++i) {
|
||||
b2a->grid_points[i] = mftTag->grid_points[0];
|
||||
}
|
||||
// The grid only makes sense with at least two points along each axis
|
||||
if (a2b->grid_points[0] < 2) {
|
||||
if (b2a->grid_points[0] < 2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// ...for B2A, exactly 3 *input* channels and 1-4 *output* channels.
|
||||
if (b2a->input_channels != ARRAY_COUNT(b2a->input_curves)) {
|
||||
return false;
|
||||
}
|
||||
if (b2a->output_channels < 1 || b2a->output_channels > ARRAY_COUNT(b2a->output_curves)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool init_a2b_tables(const uint8_t* table_base, uint64_t max_tables_len, uint32_t byte_width,
|
||||
uint32_t input_table_entries, uint32_t output_table_entries,
|
||||
skcms_A2B* a2b) {
|
||||
template <typename A2B_or_B2A>
|
||||
static bool init_tables(const uint8_t* table_base, uint64_t max_tables_len, uint32_t byte_width,
|
||||
uint32_t input_table_entries, uint32_t output_table_entries,
|
||||
A2B_or_B2A* out) {
|
||||
// byte_width is 1 or 2, [input|output]_table_entries are in [2, 4096], so no overflow
|
||||
uint32_t byte_len_per_input_table = input_table_entries * byte_width;
|
||||
uint32_t byte_len_per_output_table = output_table_entries * byte_width;
|
||||
|
||||
// [input|output]_channels are <= 4, so still no overflow
|
||||
uint32_t byte_len_all_input_tables = a2b->input_channels * byte_len_per_input_table;
|
||||
uint32_t byte_len_all_output_tables = a2b->output_channels * byte_len_per_output_table;
|
||||
uint32_t byte_len_all_input_tables = out->input_channels * byte_len_per_input_table;
|
||||
uint32_t byte_len_all_output_tables = out->output_channels * byte_len_per_output_table;
|
||||
|
||||
uint64_t grid_size = a2b->output_channels * byte_width;
|
||||
for (uint32_t axis = 0; axis < a2b->input_channels; ++axis) {
|
||||
grid_size *= a2b->grid_points[axis];
|
||||
uint64_t grid_size = out->output_channels * byte_width;
|
||||
for (uint32_t axis = 0; axis < out->input_channels; ++axis) {
|
||||
grid_size *= out->grid_points[axis];
|
||||
}
|
||||
|
||||
if (max_tables_len < byte_len_all_input_tables + grid_size + byte_len_all_output_tables) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < a2b->input_channels; ++i) {
|
||||
a2b->input_curves[i].table_entries = input_table_entries;
|
||||
for (uint32_t i = 0; i < out->input_channels; ++i) {
|
||||
out->input_curves[i].table_entries = input_table_entries;
|
||||
if (byte_width == 1) {
|
||||
a2b->input_curves[i].table_8 = table_base + i * byte_len_per_input_table;
|
||||
a2b->input_curves[i].table_16 = nullptr;
|
||||
out->input_curves[i].table_8 = table_base + i * byte_len_per_input_table;
|
||||
out->input_curves[i].table_16 = nullptr;
|
||||
} else {
|
||||
a2b->input_curves[i].table_8 = nullptr;
|
||||
a2b->input_curves[i].table_16 = table_base + i * byte_len_per_input_table;
|
||||
out->input_curves[i].table_8 = nullptr;
|
||||
out->input_curves[i].table_16 = table_base + i * byte_len_per_input_table;
|
||||
}
|
||||
}
|
||||
|
||||
if (byte_width == 1) {
|
||||
a2b->grid_8 = table_base + byte_len_all_input_tables;
|
||||
a2b->grid_16 = nullptr;
|
||||
out->grid_8 = table_base + byte_len_all_input_tables;
|
||||
out->grid_16 = nullptr;
|
||||
} else {
|
||||
a2b->grid_8 = nullptr;
|
||||
a2b->grid_16 = table_base + byte_len_all_input_tables;
|
||||
out->grid_8 = nullptr;
|
||||
out->grid_16 = table_base + byte_len_all_input_tables;
|
||||
}
|
||||
|
||||
const uint8_t* output_table_base = table_base + byte_len_all_input_tables + grid_size;
|
||||
for (uint32_t i = 0; i < a2b->output_channels; ++i) {
|
||||
a2b->output_curves[i].table_entries = output_table_entries;
|
||||
for (uint32_t i = 0; i < out->output_channels; ++i) {
|
||||
out->output_curves[i].table_entries = output_table_entries;
|
||||
if (byte_width == 1) {
|
||||
a2b->output_curves[i].table_8 = output_table_base + i * byte_len_per_output_table;
|
||||
a2b->output_curves[i].table_16 = nullptr;
|
||||
out->output_curves[i].table_8 = output_table_base + i * byte_len_per_output_table;
|
||||
out->output_curves[i].table_16 = nullptr;
|
||||
} else {
|
||||
a2b->output_curves[i].table_8 = nullptr;
|
||||
a2b->output_curves[i].table_16 = output_table_base + i * byte_len_per_output_table;
|
||||
out->output_curves[i].table_8 = nullptr;
|
||||
out->output_curves[i].table_16 = output_table_base + i * byte_len_per_output_table;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool read_tag_mft1(const skcms_ICCTag* tag, skcms_A2B* a2b) {
|
||||
template <typename A2B_or_B2A>
|
||||
static bool read_tag_mft1(const skcms_ICCTag* tag, A2B_or_B2A* out) {
|
||||
if (tag->size < SAFE_FIXED_SIZE(mft1_Layout)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const mft1_Layout* mftTag = (const mft1_Layout*)tag->buf;
|
||||
if (!read_mft_common(mftTag->common, a2b)) {
|
||||
if (!read_mft_common(mftTag->common, out)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t input_table_entries = 256;
|
||||
uint32_t output_table_entries = 256;
|
||||
|
||||
return init_a2b_tables(mftTag->variable, tag->size - SAFE_FIXED_SIZE(mft1_Layout), 1,
|
||||
input_table_entries, output_table_entries, a2b);
|
||||
return init_tables(mftTag->variable, tag->size - SAFE_FIXED_SIZE(mft1_Layout), 1,
|
||||
input_table_entries, output_table_entries, out);
|
||||
}
|
||||
|
||||
static bool read_tag_mft2(const skcms_ICCTag* tag, skcms_A2B* a2b) {
|
||||
template <typename A2B_or_B2A>
|
||||
static bool read_tag_mft2(const skcms_ICCTag* tag, A2B_or_B2A* out) {
|
||||
if (tag->size < SAFE_FIXED_SIZE(mft2_Layout)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const mft2_Layout* mftTag = (const mft2_Layout*)tag->buf;
|
||||
if (!read_mft_common(mftTag->common, a2b)) {
|
||||
if (!read_mft_common(mftTag->common, out)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -719,8 +749,8 @@ static bool read_tag_mft2(const skcms_ICCTag* tag, skcms_A2B* a2b) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return init_a2b_tables(mftTag->variable, tag->size - SAFE_FIXED_SIZE(mft2_Layout), 2,
|
||||
input_table_entries, output_table_entries, a2b);
|
||||
return init_tables(mftTag->variable, tag->size - SAFE_FIXED_SIZE(mft2_Layout), 2,
|
||||
input_table_entries, output_table_entries, out);
|
||||
}
|
||||
|
||||
static bool read_curves(const uint8_t* buf, uint32_t size, uint32_t curve_offset,
|
||||
@ -750,6 +780,7 @@ static bool read_curves(const uint8_t* buf, uint32_t size, uint32_t curve_offset
|
||||
return true;
|
||||
}
|
||||
|
||||
// mAB and mBA tags use the same encoding, including color lookup tables.
|
||||
typedef struct {
|
||||
uint8_t type [ 4];
|
||||
uint8_t reserved_a [ 4];
|
||||
@ -761,21 +792,21 @@ typedef struct {
|
||||
uint8_t m_curve_offset [ 4];
|
||||
uint8_t clut_offset [ 4];
|
||||
uint8_t a_curve_offset [ 4];
|
||||
} mAB_Layout;
|
||||
} mAB_or_mBA_Layout;
|
||||
|
||||
typedef struct {
|
||||
uint8_t grid_points [16];
|
||||
uint8_t grid_byte_width [ 1];
|
||||
uint8_t reserved [ 3];
|
||||
uint8_t variable [1/*variable*/];
|
||||
} mABCLUT_Layout;
|
||||
} CLUT_Layout;
|
||||
|
||||
static bool read_tag_mab(const skcms_ICCTag* tag, skcms_A2B* a2b, bool pcs_is_xyz) {
|
||||
if (tag->size < SAFE_SIZEOF(mAB_Layout)) {
|
||||
if (tag->size < SAFE_SIZEOF(mAB_or_mBA_Layout)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const mAB_Layout* mABTag = (const mAB_Layout*)tag->buf;
|
||||
const mAB_or_mBA_Layout* mABTag = (const mAB_or_mBA_Layout*)tag->buf;
|
||||
|
||||
a2b->input_channels = mABTag->input_channels[0];
|
||||
a2b->output_channels = mABTag->output_channels[0];
|
||||
@ -820,11 +851,11 @@ static bool read_tag_mab(const skcms_ICCTag* tag, skcms_A2B* a2b, bool pcs_is_xy
|
||||
if (tag->size < matrix_offset + 12 * SAFE_SIZEOF(uint32_t)) {
|
||||
return false;
|
||||
}
|
||||
float encoding_factor = pcs_is_xyz ? 65535 / 32768.0f : 1.0f;
|
||||
float encoding_factor = pcs_is_xyz ? (65535 / 32768.0f) : 1.0f;
|
||||
const uint8_t* mtx_buf = tag->buf + matrix_offset;
|
||||
a2b->matrix.vals[0][0] = encoding_factor * read_big_fixed(mtx_buf + 0);
|
||||
a2b->matrix.vals[0][1] = encoding_factor * read_big_fixed(mtx_buf + 4);
|
||||
a2b->matrix.vals[0][2] = encoding_factor * read_big_fixed(mtx_buf + 8);
|
||||
a2b->matrix.vals[0][0] = encoding_factor * read_big_fixed(mtx_buf + 0);
|
||||
a2b->matrix.vals[0][1] = encoding_factor * read_big_fixed(mtx_buf + 4);
|
||||
a2b->matrix.vals[0][2] = encoding_factor * read_big_fixed(mtx_buf + 8);
|
||||
a2b->matrix.vals[1][0] = encoding_factor * read_big_fixed(mtx_buf + 12);
|
||||
a2b->matrix.vals[1][1] = encoding_factor * read_big_fixed(mtx_buf + 16);
|
||||
a2b->matrix.vals[1][2] = encoding_factor * read_big_fixed(mtx_buf + 20);
|
||||
@ -851,10 +882,10 @@ static bool read_tag_mab(const skcms_ICCTag* tag, skcms_A2B* a2b, bool pcs_is_xy
|
||||
return false;
|
||||
}
|
||||
|
||||
if (tag->size < clut_offset + SAFE_FIXED_SIZE(mABCLUT_Layout)) {
|
||||
if (tag->size < clut_offset + SAFE_FIXED_SIZE(CLUT_Layout)) {
|
||||
return false;
|
||||
}
|
||||
const mABCLUT_Layout* clut = (const mABCLUT_Layout*)(tag->buf + clut_offset);
|
||||
const CLUT_Layout* clut = (const CLUT_Layout*)(tag->buf + clut_offset);
|
||||
|
||||
if (clut->grid_byte_width[0] == 1) {
|
||||
a2b->grid_8 = clut->variable;
|
||||
@ -866,7 +897,7 @@ static bool read_tag_mab(const skcms_ICCTag* tag, skcms_A2B* a2b, bool pcs_is_xy
|
||||
return false;
|
||||
}
|
||||
|
||||
uint64_t grid_size = a2b->output_channels * clut->grid_byte_width[0];
|
||||
uint64_t grid_size = a2b->output_channels * clut->grid_byte_width[0]; // the payload
|
||||
for (uint32_t i = 0; i < a2b->input_channels; ++i) {
|
||||
a2b->grid_points[i] = clut->grid_points[i];
|
||||
// The grid only makes sense with at least two points along each axis
|
||||
@ -875,7 +906,7 @@ static bool read_tag_mab(const skcms_ICCTag* tag, skcms_A2B* a2b, bool pcs_is_xy
|
||||
}
|
||||
grid_size *= a2b->grid_points[i];
|
||||
}
|
||||
if (tag->size < clut_offset + SAFE_FIXED_SIZE(mABCLUT_Layout) + grid_size) {
|
||||
if (tag->size < clut_offset + SAFE_FIXED_SIZE(CLUT_Layout) + grid_size) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
@ -895,6 +926,129 @@ static bool read_tag_mab(const skcms_ICCTag* tag, skcms_A2B* a2b, bool pcs_is_xy
|
||||
return true;
|
||||
}
|
||||
|
||||
// Exactly the same as read_tag_mab(), except where there are comments.
|
||||
// TODO: refactor the two to eliminate common code?
|
||||
static bool read_tag_mba(const skcms_ICCTag* tag, skcms_B2A* b2a, bool pcs_is_xyz) {
|
||||
if (tag->size < SAFE_SIZEOF(mAB_or_mBA_Layout)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const mAB_or_mBA_Layout* mBATag = (const mAB_or_mBA_Layout*)tag->buf;
|
||||
|
||||
b2a->input_channels = mBATag->input_channels[0];
|
||||
b2a->output_channels = mBATag->output_channels[0];
|
||||
|
||||
// Input and output arity requirements swapped... |inputs|==3, |outputs|<=4.
|
||||
if (b2a->input_channels != ARRAY_COUNT(b2a->input_curves)) {
|
||||
return false;
|
||||
}
|
||||
if (b2a->output_channels > ARRAY_COUNT(b2a->output_curves)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t b_curve_offset = read_big_u32(mBATag->b_curve_offset);
|
||||
uint32_t matrix_offset = read_big_u32(mBATag->matrix_offset);
|
||||
uint32_t m_curve_offset = read_big_u32(mBATag->m_curve_offset);
|
||||
uint32_t clut_offset = read_big_u32(mBATag->clut_offset);
|
||||
uint32_t a_curve_offset = read_big_u32(mBATag->a_curve_offset);
|
||||
|
||||
if (0 == b_curve_offset) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// "B" curves are our inputs, not outputs.
|
||||
if (!read_curves(tag->buf, tag->size, b_curve_offset, b2a->input_channels,
|
||||
b2a->input_curves)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (0 != m_curve_offset) {
|
||||
if (0 == matrix_offset) {
|
||||
return false;
|
||||
}
|
||||
// Matrix channels is tied to input_channels (3), not output_channels (1-4).
|
||||
b2a->matrix_channels = b2a->input_channels;
|
||||
|
||||
if (!read_curves(tag->buf, tag->size, m_curve_offset, b2a->matrix_channels,
|
||||
b2a->matrix_curves)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (tag->size < matrix_offset + 12 * SAFE_SIZEOF(uint32_t)) {
|
||||
return false;
|
||||
}
|
||||
float encoding_factor = pcs_is_xyz ? (65535 / 32768.0f) : 1.0f;
|
||||
const uint8_t* mtx_buf = tag->buf + matrix_offset;
|
||||
b2a->matrix.vals[0][0] = encoding_factor * read_big_fixed(mtx_buf + 0);
|
||||
b2a->matrix.vals[0][1] = encoding_factor * read_big_fixed(mtx_buf + 4);
|
||||
b2a->matrix.vals[0][2] = encoding_factor * read_big_fixed(mtx_buf + 8);
|
||||
b2a->matrix.vals[1][0] = encoding_factor * read_big_fixed(mtx_buf + 12);
|
||||
b2a->matrix.vals[1][1] = encoding_factor * read_big_fixed(mtx_buf + 16);
|
||||
b2a->matrix.vals[1][2] = encoding_factor * read_big_fixed(mtx_buf + 20);
|
||||
b2a->matrix.vals[2][0] = encoding_factor * read_big_fixed(mtx_buf + 24);
|
||||
b2a->matrix.vals[2][1] = encoding_factor * read_big_fixed(mtx_buf + 28);
|
||||
b2a->matrix.vals[2][2] = encoding_factor * read_big_fixed(mtx_buf + 32);
|
||||
b2a->matrix.vals[0][3] = encoding_factor * read_big_fixed(mtx_buf + 36);
|
||||
b2a->matrix.vals[1][3] = encoding_factor * read_big_fixed(mtx_buf + 40);
|
||||
b2a->matrix.vals[2][3] = encoding_factor * read_big_fixed(mtx_buf + 44);
|
||||
} else {
|
||||
if (0 != matrix_offset) {
|
||||
return false;
|
||||
}
|
||||
b2a->matrix_channels = 0;
|
||||
}
|
||||
|
||||
if (0 != a_curve_offset) {
|
||||
if (0 == clut_offset) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// "A" curves are our output, not input.
|
||||
if (!read_curves(tag->buf, tag->size, a_curve_offset, b2a->output_channels,
|
||||
b2a->output_curves)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (tag->size < clut_offset + SAFE_FIXED_SIZE(CLUT_Layout)) {
|
||||
return false;
|
||||
}
|
||||
const CLUT_Layout* clut = (const CLUT_Layout*)(tag->buf + clut_offset);
|
||||
|
||||
if (clut->grid_byte_width[0] == 1) {
|
||||
b2a->grid_8 = clut->variable;
|
||||
b2a->grid_16 = nullptr;
|
||||
} else if (clut->grid_byte_width[0] == 2) {
|
||||
b2a->grid_8 = nullptr;
|
||||
b2a->grid_16 = clut->variable;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint64_t grid_size = b2a->output_channels * clut->grid_byte_width[0];
|
||||
for (uint32_t i = 0; i < b2a->input_channels; ++i) {
|
||||
b2a->grid_points[i] = clut->grid_points[i];
|
||||
if (b2a->grid_points[i] < 2) {
|
||||
return false;
|
||||
}
|
||||
grid_size *= b2a->grid_points[i];
|
||||
}
|
||||
if (tag->size < clut_offset + SAFE_FIXED_SIZE(CLUT_Layout) + grid_size) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (0 != clut_offset) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (b2a->input_channels != b2a->output_channels) {
|
||||
return false;
|
||||
}
|
||||
|
||||
b2a->input_channels = 0;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// If you pass f, we'll fit a possibly-non-zero value for *f.
|
||||
// If you pass nullptr, we'll assume you want *f to be treated as zero.
|
||||
static int fit_linear(const skcms_Curve* curve, int N, float tol,
|
||||
@ -949,51 +1103,70 @@ static int fit_linear(const skcms_Curve* curve, int N, float tol,
|
||||
return lin_points;
|
||||
}
|
||||
|
||||
// If this skcms_Curve holds an identity table, rewrite it as an identity skcms_TransferFunction.
|
||||
static void canonicalize_identity(skcms_Curve* curve) {
|
||||
if (curve->table_entries && curve->table_entries <= (uint32_t)INT_MAX) {
|
||||
int N = (int)curve->table_entries;
|
||||
|
||||
float c = 0.0f, d = 0.0f, f = 0.0f;
|
||||
if (N == fit_linear(curve, N, 1.0f/(2*N), &c,&d,&f)
|
||||
&& c == 1.0f
|
||||
&& f == 0.0f) {
|
||||
curve->table_entries = 0;
|
||||
curve->table_8 = nullptr;
|
||||
curve->table_16 = nullptr;
|
||||
curve->parametric = skcms_TransferFunction{1,1,0,0,0,0,0};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool read_a2b(const skcms_ICCTag* tag, skcms_A2B* a2b, bool pcs_is_xyz) {
|
||||
bool ok = false;
|
||||
if (tag->type == skcms_Signature_mft1) {
|
||||
ok = read_tag_mft1(tag, a2b);
|
||||
} else if (tag->type == skcms_Signature_mft2) {
|
||||
ok = read_tag_mft2(tag, a2b);
|
||||
} else if (tag->type == skcms_Signature_mAB) {
|
||||
ok = read_tag_mab(tag, a2b, pcs_is_xyz);
|
||||
}
|
||||
if (tag->type == skcms_Signature_mft1) { ok = read_tag_mft1(tag, a2b); }
|
||||
if (tag->type == skcms_Signature_mft2) { ok = read_tag_mft2(tag, a2b); }
|
||||
if (tag->type == skcms_Signature_mAB ) { ok = read_tag_mab(tag, a2b, pcs_is_xyz); }
|
||||
if (!ok) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Detect and canonicalize identity tables.
|
||||
skcms_Curve* curves[] = {
|
||||
a2b->input_channels > 0 ? a2b->input_curves + 0 : nullptr,
|
||||
a2b->input_channels > 1 ? a2b->input_curves + 1 : nullptr,
|
||||
a2b->input_channels > 2 ? a2b->input_curves + 2 : nullptr,
|
||||
a2b->input_channels > 3 ? a2b->input_curves + 3 : nullptr,
|
||||
a2b->matrix_channels > 0 ? a2b->matrix_curves + 0 : nullptr,
|
||||
a2b->matrix_channels > 1 ? a2b->matrix_curves + 1 : nullptr,
|
||||
a2b->matrix_channels > 2 ? a2b->matrix_curves + 2 : nullptr,
|
||||
a2b->output_channels > 0 ? a2b->output_curves + 0 : nullptr,
|
||||
a2b->output_channels > 1 ? a2b->output_curves + 1 : nullptr,
|
||||
a2b->output_channels > 2 ? a2b->output_curves + 2 : nullptr,
|
||||
};
|
||||
if (a2b->input_channels > 0) { canonicalize_identity(a2b->input_curves + 0); }
|
||||
if (a2b->input_channels > 1) { canonicalize_identity(a2b->input_curves + 1); }
|
||||
if (a2b->input_channels > 2) { canonicalize_identity(a2b->input_curves + 2); }
|
||||
if (a2b->input_channels > 3) { canonicalize_identity(a2b->input_curves + 3); }
|
||||
|
||||
for (int i = 0; i < ARRAY_COUNT(curves); i++) {
|
||||
skcms_Curve* curve = curves[i];
|
||||
if (a2b->matrix_channels > 0) { canonicalize_identity(a2b->matrix_curves + 0); }
|
||||
if (a2b->matrix_channels > 1) { canonicalize_identity(a2b->matrix_curves + 1); }
|
||||
if (a2b->matrix_channels > 2) { canonicalize_identity(a2b->matrix_curves + 2); }
|
||||
|
||||
if (curve && curve->table_entries && curve->table_entries <= (uint32_t)INT_MAX) {
|
||||
int N = (int)curve->table_entries;
|
||||
if (a2b->output_channels > 0) { canonicalize_identity(a2b->output_curves + 0); }
|
||||
if (a2b->output_channels > 1) { canonicalize_identity(a2b->output_curves + 1); }
|
||||
if (a2b->output_channels > 2) { canonicalize_identity(a2b->output_curves + 2); }
|
||||
|
||||
float c = 0.0f, d = 0.0f, f = 0.0f;
|
||||
if (N == fit_linear(curve, N, 1.0f/(2*N), &c,&d,&f)
|
||||
&& c == 1.0f
|
||||
&& f == 0.0f) {
|
||||
curve->table_entries = 0;
|
||||
curve->table_8 = nullptr;
|
||||
curve->table_16 = nullptr;
|
||||
curve->parametric = skcms_TransferFunction{1,1,0,0,0,0,0};
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool read_b2a(const skcms_ICCTag* tag, skcms_B2A* b2a, bool pcs_is_xyz) {
|
||||
bool ok = false;
|
||||
if (tag->type == skcms_Signature_mft1) { ok = read_tag_mft1(tag, b2a); }
|
||||
if (tag->type == skcms_Signature_mft2) { ok = read_tag_mft2(tag, b2a); }
|
||||
if (tag->type == skcms_Signature_mBA ) { ok = read_tag_mba(tag, b2a, pcs_is_xyz); }
|
||||
if (!ok) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (b2a->input_channels > 0) { canonicalize_identity(b2a->input_curves + 0); }
|
||||
if (b2a->input_channels > 1) { canonicalize_identity(b2a->input_curves + 1); }
|
||||
if (b2a->input_channels > 2) { canonicalize_identity(b2a->input_curves + 2); }
|
||||
|
||||
if (b2a->matrix_channels > 0) { canonicalize_identity(b2a->matrix_curves + 0); }
|
||||
if (b2a->matrix_channels > 1) { canonicalize_identity(b2a->matrix_curves + 1); }
|
||||
if (b2a->matrix_channels > 2) { canonicalize_identity(b2a->matrix_curves + 2); }
|
||||
|
||||
if (b2a->output_channels > 0) { canonicalize_identity(b2a->output_curves + 0); }
|
||||
if (b2a->output_channels > 1) { canonicalize_identity(b2a->output_curves + 1); }
|
||||
if (b2a->output_channels > 2) { canonicalize_identity(b2a->output_curves + 2); }
|
||||
if (b2a->output_channels > 3) { canonicalize_identity(b2a->output_curves + 3); }
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1132,16 +1305,15 @@ bool skcms_ParseWithA2BPriority(const void* buf, size_t len,
|
||||
}
|
||||
}
|
||||
|
||||
skcms_ICCTag a2b_tag;
|
||||
|
||||
for (int i = 0; i < priorities; i++) {
|
||||
// enum { perceptual, relative_colormetric, saturation }
|
||||
if (priority[i] < 0 || priority[i] > 2) {
|
||||
return false;
|
||||
}
|
||||
uint32_t sig = skcms_Signature_A2B0 + static_cast<uint32_t>(priority[i]);
|
||||
if (skcms_GetTagBySignature(profile, sig, &a2b_tag)) {
|
||||
if (!read_a2b(&a2b_tag, &profile->A2B, pcs_is_xyz)) {
|
||||
skcms_ICCTag tag;
|
||||
if (skcms_GetTagBySignature(profile, sig, &tag)) {
|
||||
if (!read_a2b(&tag, &profile->A2B, pcs_is_xyz)) {
|
||||
// Malformed A2B tag
|
||||
return false;
|
||||
}
|
||||
@ -1150,6 +1322,23 @@ bool skcms_ParseWithA2BPriority(const void* buf, size_t len,
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < priorities; i++) {
|
||||
// enum { perceptual, relative_colormetric, saturation }
|
||||
if (priority[i] < 0 || priority[i] > 2) {
|
||||
return false;
|
||||
}
|
||||
uint32_t sig = skcms_Signature_B2A0 + static_cast<uint32_t>(priority[i]);
|
||||
skcms_ICCTag tag;
|
||||
if (skcms_GetTagBySignature(profile, sig, &tag)) {
|
||||
if (!read_b2a(&tag, &profile->B2A, pcs_is_xyz)) {
|
||||
// Malformed B2A tag
|
||||
return false;
|
||||
}
|
||||
profile->has_B2A = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return usable_as_src(profile);
|
||||
}
|
||||
|
||||
@ -1179,7 +1368,7 @@ const skcms_ICCProfile* skcms_sRGB_profile() {
|
||||
{ 0.013916016f, 0.097076416f, 0.714096069f },
|
||||
}},
|
||||
|
||||
false, // has_A2B, followed by a2b itself which we don't care about.
|
||||
false, // has_A2B, followed by A2B itself, which we don't care about.
|
||||
{
|
||||
0,
|
||||
{
|
||||
@ -1211,6 +1400,39 @@ const skcms_ICCProfile* skcms_sRGB_profile() {
|
||||
{{0, {0,0, 0,0,0,0,0}}},
|
||||
},
|
||||
},
|
||||
|
||||
false, // has_B2A, followed by B2A itself, which we also don't care about.
|
||||
{
|
||||
0,
|
||||
{
|
||||
{{0, {0,0, 0,0,0,0,0}}},
|
||||
{{0, {0,0, 0,0,0,0,0}}},
|
||||
{{0, {0,0, 0,0,0,0,0}}},
|
||||
},
|
||||
|
||||
0,
|
||||
{{
|
||||
{ 0,0,0,0 },
|
||||
{ 0,0,0,0 },
|
||||
{ 0,0,0,0 },
|
||||
}},
|
||||
{
|
||||
{{0, {0,0, 0,0,0,0,0}}},
|
||||
{{0, {0,0, 0,0,0,0,0}}},
|
||||
{{0, {0,0, 0,0,0,0,0}}},
|
||||
},
|
||||
|
||||
0,
|
||||
{0,0,0,0},
|
||||
nullptr,
|
||||
nullptr,
|
||||
{
|
||||
{{0, {0,0, 0,0,0,0,0}}},
|
||||
{{0, {0,0, 0,0,0,0,0}}},
|
||||
{{0, {0,0, 0,0,0,0,0}}},
|
||||
{{0, {0,0, 0,0,0,0,0}}},
|
||||
},
|
||||
},
|
||||
};
|
||||
return &sRGB_profile;
|
||||
}
|
||||
@ -1239,7 +1461,7 @@ const skcms_ICCProfile* skcms_XYZD50_profile() {
|
||||
{ 0,0,1 },
|
||||
}},
|
||||
|
||||
false, // has_A2B, followed by a2b itself which we don't care about.
|
||||
false, // has_A2B, followed by A2B itself, which we don't care about.
|
||||
{
|
||||
0,
|
||||
{
|
||||
@ -1271,6 +1493,39 @@ const skcms_ICCProfile* skcms_XYZD50_profile() {
|
||||
{{0, {0,0, 0,0,0,0,0}}},
|
||||
},
|
||||
},
|
||||
|
||||
false, // has_B2A, followed by B2A itself, which we also don't care about.
|
||||
{
|
||||
0,
|
||||
{
|
||||
{{0, {0,0, 0,0,0,0,0}}},
|
||||
{{0, {0,0, 0,0,0,0,0}}},
|
||||
{{0, {0,0, 0,0,0,0,0}}},
|
||||
},
|
||||
|
||||
0,
|
||||
{{
|
||||
{ 0,0,0,0 },
|
||||
{ 0,0,0,0 },
|
||||
{ 0,0,0,0 },
|
||||
}},
|
||||
{
|
||||
{{0, {0,0, 0,0,0,0,0}}},
|
||||
{{0, {0,0, 0,0,0,0,0}}},
|
||||
{{0, {0,0, 0,0,0,0,0}}},
|
||||
},
|
||||
|
||||
0,
|
||||
{0,0,0,0},
|
||||
nullptr,
|
||||
nullptr,
|
||||
{
|
||||
{{0, {0,0, 0,0,0,0,0}}},
|
||||
{{0, {0,0, 0,0,0,0,0}}},
|
||||
{{0, {0,0, 0,0,0,0,0}}},
|
||||
{{0, {0,0, 0,0,0,0,0}}},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
return &XYZD50_profile;
|
||||
|
2
third_party/skcms/version.sha1
vendored
2
third_party/skcms/version.sha1
vendored
@ -1 +1 @@
|
||||
b9593d4e39ea3dbf1ba5e894f0cefc1cb1568437
|
||||
4e8691e281941320a5644d50c566c2d4394cf1c8
|
||||
|
Loading…
Reference in New Issue
Block a user