33constexpr size_t kNumChannels = 3;
36constexpr float kD50_x = 0.9642f;
37constexpr float kD50_y = 1.0000f;
38constexpr float kD50_z = 0.8249f;
44SkFixed float_round_to_fixed(
float x) {
49uint16_t float_to_uInt16Number(
float x, uint16_t one) {
51 if (
x > one)
return one;
53 return static_cast<uint16_t
>(
x);
57constexpr uint16_t kOne16CurveType = 0xFFFF;
61constexpr uint16_t kOne16XYZ = 0x8000;
68 uint32_t cmm_type = 0;
86 uint16_t creation_date_hours = 0;
87 uint16_t creation_date_minutes = 0;
88 uint16_t creation_date_seconds = 0;
94 uint32_t platform = 0;
97 uint32_t
flags = 0x00000000;
100 uint32_t device_manufacturer = 0;
103 uint32_t device_model = 0;
106 uint8_t device_attributes[8] = {0};
117 uint32_t creator = 0;
120 uint8_t profile_id[16] = {0};
123 uint8_t reserved[28] = {0};
126 uint32_t tag_count = 0;
144 for (
int i = 0; i < 3; ++i) {
145 for (
int j = 0; j < 3; ++j) {
149 for (
int i = 0; i < 3; ++i) {
163 static constexpr float kTolerance = 1.0f / (1 << 11);
179 for (
int r = 0; r < 3; r++) {
180 for (
int c = 0; c < 3; c++) {
189constexpr uint32_t kCICPPrimariesSRGB = 1;
190constexpr uint32_t kCICPPrimariesP3 = 12;
191constexpr uint32_t kCICPPrimariesRec2020 = 9;
195 return kCICPPrimariesSRGB;
197 return kCICPPrimariesP3;
199 return kCICPPrimariesRec2020;
204constexpr uint32_t kCICPTrfnSRGB = 1;
205constexpr uint32_t kCICPTrfn2Dot2 = 4;
206constexpr uint32_t kCICPTrfnLinear = 8;
207constexpr uint32_t kCICPTrfnPQ = 16;
208constexpr uint32_t kCICPTrfnHLG = 18;
216 return kCICPTrfnSRGB;
218 return kCICPTrfn2Dot2;
220 return kCICPTrfnLinear;
238 const uint32_t cicp_trfn = get_cicp_trfn(fn);
239 const uint32_t cicp_primaries = get_cicp_primaries(toXYZD50);
242 if (cicp_trfn == kCICPPrimariesSRGB && cicp_primaries == kCICPTrfnSRGB) {
247 if (cicp_primaries && cicp_trfn) {
249 switch (cicp_primaries) {
250 case kCICPPrimariesSRGB:
253 case kCICPPrimariesP3:
256 case kCICPPrimariesRec2020:
268 case kCICPTrfnLinear:
290 md5.write(&toXYZD50,
sizeof(toXYZD50));
291 md5.write(&fn,
sizeof(fn));
297 uint32_t text_length = strlen(
text);
309 for (
size_t i = 0; i < text_length; i++) {
315 return s.detachAsData();
327 return s.detachAsData();
330constexpr float kToneMapInputMax = 1000.f / 203.f;
331constexpr float kToneMapOutputMax = 1.f;
334float tone_map_gain(
float x) {
338 constexpr float kToneMapA = kToneMapOutputMax / (kToneMapInputMax * kToneMapInputMax);
339 constexpr float kToneMapB = 1.f / kToneMapOutputMax;
340 return (1.f + kToneMapA *
x) / (1.f + kToneMapB *
x);
344float tone_map_inverse(
float y) {
345 constexpr float kToneMapA = kToneMapOutputMax / (kToneMapInputMax * kToneMapInputMax);
346 constexpr float kToneMapB = 1.f / kToneMapOutputMax;
349 const float a = kToneMapA;
350 const float b = (1 - kToneMapB *
y);
352 const float discriminant =
b *
b - 4.f *
a * c;
353 if (discriminant < 0.f) {
356 return (-
b + sqrtf(discriminant)) / (2.f *
a);
365 x *= std::pow(
x, 0.2);
369 x = std::min(
x, 1.f);
373 x *= kToneMapInputMax;
385 uint16_t
value =
reinterpret_cast<const uint16_t*
>(trc.
table_16)[i];
393 if (fn.
a == 1.f && fn.
b == 0.f && fn.
c == 0.f && fn.
d == 0.f && fn.
e == 0.f &&
409 return s.detachAsData();
412sk_sp<SkData> write_clut(
const uint8_t* grid_points,
const uint8_t* grid_16) {
414 for (
size_t i = 0; i < 16; ++i) {
415 s.write8(i < kNumChannels ? grid_points[i] : 0);
422 uint32_t value_count = kNumChannels;
423 for (uint32_t i = 0; i < kNumChannels; ++i) {
424 value_count *= grid_points[i];
426 for (uint32_t i = 0; i < value_count; ++i) {
427 uint16_t
value =
reinterpret_cast<const uint16_t*
>(grid_16)[i];
431 return s.detachAsData();
438 const uint8_t* grid_points,
439 const uint8_t* grid_16,
445 size_t b_curves_offset =
offset;
448 for (
size_t i = 0; i < kNumChannels; ++i) {
449 b_curves_data[i] = write_trc_tag(b_curves[i]);
451 offset += b_curves_data[i]->size();
455 size_t clut_offset = 0;
460 clut = write_clut(grid_points, grid_16);
466 size_t a_curves_offset = 0;
472 for (
size_t i = 0; i < kNumChannels; ++i) {
473 a_curves_data[i] = write_trc_tag(a_curves[i]);
475 offset += a_curves_data[i]->size();
480 size_t matrix_offset = 0;
485 matrix_data = write_matrix(matrix);
486 offset += matrix_data->size();
490 size_t m_curves_offset = 0;
495 for (
size_t i = 0; i < kNumChannels; ++i) {
496 m_curves_data[i] = write_trc_tag(m_curves[i]);
498 offset += m_curves_data[i]->size();
505 s.write8(kNumChannels);
506 s.write8(kNumChannels);
513 SkASSERT(
s.bytesWritten() == b_curves_offset);
514 for (
size_t i = 0; i < kNumChannels; ++i) {
515 s.write(b_curves_data[i]->
data(), b_curves_data[i]->
size());
518 SkASSERT(
s.bytesWritten() == clut_offset);
522 SkASSERT(
s.bytesWritten() == a_curves_offset);
523 for (
size_t i = 0; i < kNumChannels; ++i) {
524 s.write(a_curves_data[i]->
data(), a_curves_data[i]->
size());
528 SkASSERT(
s.bytesWritten() == matrix_offset);
529 s.write(matrix_data->data(), matrix_data->size());
532 SkASSERT(
s.bytesWritten() == m_curves_offset);
533 for (
size_t i = 0; i < kNumChannels; ++i) {
534 s.write(m_curves_data[i]->
data(), m_curves_data[i]->
size());
537 return s.detachAsData();
545 std::vector<std::pair<uint32_t, sk_sp<SkData>>> tags;
548 if (profile->has_toXYZD50) {
549 const auto& m = profile->toXYZD50;
550 tags.emplace_back(
kTAG_rXYZ, write_xyz_tag(m.vals[0][0], m.vals[1][0], m.vals[2][0]));
551 tags.emplace_back(
kTAG_gXYZ, write_xyz_tag(m.vals[0][1], m.vals[1][1], m.vals[2][1]));
552 tags.emplace_back(
kTAG_bXYZ, write_xyz_tag(m.vals[0][2], m.vals[1][2], m.vals[2][2]));
556 tags.emplace_back(
kTAG_wtpt, write_xyz_tag(kD50_x, kD50_y, kD50_z));
559 if (profile->has_trc) {
560 tags.emplace_back(
kTAG_rTRC, write_trc_tag(profile->trc[0]));
564 if (!memcmp(&profile->trc[1], &profile->trc[0],
sizeof(profile->trc[0]))) {
567 tags.emplace_back(
kTAG_gTRC, write_trc_tag(profile->trc[1]));
570 if (!memcmp(&profile->trc[2], &profile->trc[1],
sizeof(profile->trc[1]))) {
573 tags.emplace_back(
kTAG_bTRC, write_trc_tag(profile->trc[2]));
578 if (profile->has_CICP) {
581 tags.emplace_back(
kTAG_cicp, write_cicp_tag(profile->CICP));
585 if (profile->has_A2B) {
586 const auto& a2b = profile->A2B;
587 SkASSERT(a2b.output_channels == kNumChannels);
590 a2b.input_channels ? a2b.input_curves :
nullptr,
591 a2b.input_channels ? a2b.grid_points :
nullptr,
592 a2b.input_channels ? a2b.grid_16 :
nullptr,
593 a2b.matrix_channels ? a2b.matrix_curves :
nullptr,
594 a2b.matrix_channels ? &a2b.matrix :
nullptr);
595 tags.emplace_back(
kTAG_A2B0, std::move(a2b_data));
599 if (profile->has_B2A) {
600 const auto& b2a = profile->B2A;
601 SkASSERT(b2a.input_channels == kNumChannels);
604 b2a.output_channels ? b2a.input_curves :
nullptr,
605 b2a.output_channels ? b2a.grid_points :
nullptr,
606 b2a.output_channels ? b2a.grid_16 :
nullptr,
607 b2a.matrix_channels ? b2a.matrix_curves :
nullptr,
608 b2a.matrix_channels ? &b2a.matrix :
nullptr);
609 tags.emplace_back(
kTAG_B2A0, std::move(b2a_data));
613 tags.emplace_back(
kTAG_cprt, write_text_tag(
"Google Inc. 2016"));
616 std::string generatedDesc;
617 if (!desc || *desc ==
'\0') {
619 for (
const auto& tag : tags) {
620 md5.write(&tag.first,
sizeof(tag.first));
621 md5.write(tag.second->bytes(), tag.second->size());
625 desc = generatedDesc.c_str();
628 tags.emplace(tags.begin(),
kTAG_desc, write_text_tag(desc));
631 size_t tag_data_size = 0;
632 for (
const auto& tag : tags) {
633 tag_data_size += tag.second->size();
636 size_t profile_size =
kICCHeaderSize + tag_table_size + tag_data_size;
645 uint8_t* ptr = (uint8_t*)profile_data.
get();
652 size_t last_tag_offset =
sizeof(
header) + tag_table_size;
653 size_t last_tag_size = 0;
654 for (
const auto& tag : tags) {
655 if (!tag.second->isEmpty()) {
656 last_tag_offset = last_tag_offset + last_tag_size;
657 last_tag_size = tag.second->size();
659 uint32_t tag_table_entry[3] = {
664 memcpy(ptr, tag_table_entry,
sizeof(tag_table_entry));
665 ptr +=
sizeof(tag_table_entry);
669 for (
const auto& tag : tags) {
670 if (tag.second->isEmpty())
continue;
671 memcpy(ptr, tag.second->data(), tag.second->size());
672 ptr += tag.second->size();
675 SkASSERT(profile_size ==
static_cast<size_t>(ptr - (uint8_t*)profile_data.
get()));
681 memset(&profile, 0,
sizeof(profile));
682 std::vector<uint16_t> trc_table;
683 std::vector<uint16_t> a2b_grid;
690 profile.has_toXYZD50 =
true;
691 profile.toXYZD50 = toXYZD50;
696 profile.has_trc =
true;
697 profile.trc[0].table_entries = 0;
698 profile.trc[0].parametric = fn;
699 memcpy(&profile.trc[1], &profile.trc[0],
sizeof(profile.trc[0]));
700 memcpy(&profile.trc[2], &profile.trc[0],
sizeof(profile.trc[0]));
706 constexpr uint32_t kTrcTableSize = 65;
707 trc_table.resize(kTrcTableSize);
708 for (uint32_t i = 0; i < kTrcTableSize; ++i) {
709 float x = i / (kTrcTableSize - 1.f);
710 x = hdr_trfn_eval(fn,
x);
711 x *= tone_map_gain(
x);
716 constexpr uint32_t kGridSize = 11;
717 a2b_grid.resize(kGridSize * kGridSize * kGridSize * kNumChannels);
718 size_t a2b_grid_index = 0;
719 for (uint32_t r_index = 0; r_index < kGridSize; ++r_index) {
720 for (uint32_t g_index = 0; g_index < kGridSize; ++g_index) {
721 for (uint32_t b_index = 0; b_index < kGridSize; ++b_index) {
723 r_index / (kGridSize - 1.f),
724 g_index / (kGridSize - 1.f),
725 b_index / (kGridSize - 1.f),
729 for (
auto& c : rgb) {
730 c = tone_map_inverse(c);
736 for (
auto& c : rgb) {
737 c /= kToneMapInputMax;
741 for (
auto& c : rgb) {
742 c = std::pow(c, 1 / 1.2);
746 float Y = 0.2627f * rgb[0] + 0.6780f * rgb[1] + 0.0593f * rgb[2];
747 for (
auto& c : rgb) {
748 c *= std::pow(
Y, 0.2);
752 for (
auto& c : rgb) {
753 c *= kToneMapInputMax;
759 float max_rgb = std::max(std::max(rgb[0], rgb[1]), rgb[2]);
760 for (
auto& c : rgb) {
761 c *= tone_map_gain(0.5 * (c + max_rgb));
762 c = std::min(c, 1.f);
767 for (
const auto& c : rgb) {
768 a2b_grid[a2b_grid_index++] =
776 profile.has_A2B =
true;
777 profile.A2B.input_channels = kNumChannels;
778 profile.A2B.output_channels = kNumChannels;
779 profile.A2B.matrix_channels = kNumChannels;
780 for (
size_t i = 0; i < kNumChannels; ++i) {
781 profile.A2B.grid_points[i] = kGridSize;
783 profile.A2B.input_curves[i].table_entries = kTrcTableSize;
784 profile.A2B.input_curves[i].table_16 =
reinterpret_cast<uint8_t*
>(trc_table.data());
789 for (
size_t j = 0; j < 3; ++j) {
790 profile.A2B.matrix.vals[i][j] = toXYZD50.
vals[i][j];
792 profile.A2B.matrix.vals[i][3] = 0.f;
794 profile.A2B.grid_16 =
reinterpret_cast<const uint8_t*
>(a2b_grid.data());
797 profile.has_B2A =
true;
798 profile.B2A.input_channels = kNumChannels;
799 for (
size_t i = 0; i < 3; ++i) {
806 profile.has_CICP =
true;
807 profile.CICP.color_primaries = get_cicp_primaries(toXYZD50);
808 profile.CICP.transfer_characteristics = get_cicp_trfn(fn);
809 profile.CICP.matrix_coefficients = 0;
810 profile.CICP.video_full_range_flag = 1;
811 SkASSERT(profile.CICP.color_primaries);
812 SkASSERT(profile.CICP.transfer_characteristics);
815 std::string description = get_desc_string(fn, toXYZD50);
static SkMD5::Digest md5(const SkBitmap &bm)
static constexpr float kTolerance
#define SkEndian_SwapBE32(n)
#define SkEndian_SwapBE16(n)
static constexpr int sk_float_saturate2int(float x)
static constexpr uint32_t kTAG_mBAType
static constexpr uint32_t kTAG_desc
static constexpr uint32_t kTAG_gTRC
static constexpr uint32_t kTAG_TextType
static constexpr uint32_t kTAG_cprt
static constexpr uint32_t kXYZ_PCSSpace
static constexpr uint32_t kTAG_bTRC
static constexpr size_t kICCHeaderSize
static constexpr uint32_t kTAG_gXYZ
static constexpr uint32_t kTAG_wtpt
static constexpr uint32_t kTAG_A2B0
static constexpr uint32_t kACSP_Signature
static constexpr uint32_t kTAG_B2A0
static constexpr uint32_t kTAG_ParaCurveType
static constexpr size_t kICCTagTableEntrySize
static constexpr uint32_t kTAG_mABType
static constexpr uint32_t kTAG_bXYZ
static constexpr uint32_t kRGB_ColorSpace
static constexpr uint32_t kTAG_rXYZ
static constexpr uint32_t kDisplay_Profile
static constexpr uint32_t kTAG_rTRC
static constexpr uint32_t kTAG_cicp
@ kExponential_ParaCurveType
static constexpr uint32_t kTAG_CurveType
sk_sp< SkData > SkWriteICCProfile(const skcms_ICCProfile *profile, const char *desc)
static constexpr SkFourByteTag SkSetFourByteTag(char a, char b, char c, char d)
static sk_sp< SkData > MakeFromMalloc(const void *data, size_t length)
static sk_sp< SkData > MakeWithCopy(const void *data, size_t length)
static sk_sp< SkData > MakeEmpty()
const char * c_str() const
FlutterSemanticsFlag flags
static constexpr skcms_Matrix3x3 kSRGB
static constexpr skcms_Matrix3x3 kRec2020
static constexpr skcms_Matrix3x3 kDisplayP3
static constexpr skcms_TransferFunction k2Dot2
static constexpr skcms_TransferFunction kSRGB
static constexpr skcms_TransferFunction kHLG
static constexpr skcms_TransferFunction kPQ
static constexpr skcms_TransferFunction kLinear
unsigned useCenter Optional< SkMatrix > matrix
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot data
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
SIN Vec< N, float > floor(const Vec< N, float > &x)
static bool nearly_equal(SkColor4f x, SkColor4f y)
bool skcms_TransferFunction_isHLGish(const skcms_TransferFunction *tf)
skcms_TFType skcms_TransferFunction_getType(const skcms_TransferFunction *tf)
float skcms_TransferFunction_eval(const skcms_TransferFunction *tf, float x)
bool skcms_TransferFunction_isPQish(const skcms_TransferFunction *tf)
bool skcms_TransferFunction_isSRGBish(const skcms_TransferFunction *tf)
static const char header[]
SkString toHexString() const
uint8_t matrix_coefficients
uint8_t video_full_range_flag
uint8_t transfer_characteristics
skcms_TransferFunction parametric