679 {
681 memset(&profile, 0, sizeof(profile));
682 std::vector<uint16_t> trc_table;
683 std::vector<uint16_t> a2b_grid;
684
687
688
689 {
692 }
693
694
697 profile.trc[0].table_entries = 0;
698 profile.trc[0].parametric = fn;
701 }
702
703
705
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);
713 }
714
715
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) {
722 float rgb[3] = {
723 r_index / (kGridSize - 1.f),
724 g_index / (kGridSize - 1.f),
725 b_index / (kGridSize - 1.f),
726 };
727
728
729 for (auto& c : rgb) {
730 c = tone_map_inverse(c);
731 }
732
733
735
736 for (auto& c : rgb) {
737 c /= kToneMapInputMax;
738 }
739
740
741 for (auto& c : rgb) {
742 c = std::pow(c, 1 / 1.2);
743 }
744
745
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);
749 }
750
751
752 for (auto& c : rgb) {
753 c *= kToneMapInputMax;
754 }
755 }
756
757
758 {
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);
763 }
764 }
765
766
767 for (const auto& c : rgb) {
768 a2b_grid[a2b_grid_index++] =
770 }
771 }
772 }
773 }
774
775
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;
782
783 profile.A2B.input_curves[i].table_entries = kTrcTableSize;
784 profile.A2B.input_curves[i].table_16 =
reinterpret_cast<uint8_t*
>(trc_table.data());
785
788
789 for (size_t j = 0; j < 3; ++j) {
790 profile.A2B.matrix.vals[i][j] = toXYZD50.
vals[i][j];
791 }
792 profile.A2B.matrix.vals[i][3] = 0.f;
793 }
794 profile.A2B.grid_16 =
reinterpret_cast<const uint8_t*
>(a2b_grid.data());
795
796
798 profile.B2A.input_channels = kNumChannels;
799 for (size_t i = 0; i < 3; ++i) {
801 }
802 }
803
804
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;
813 }
814
815 std::string description = get_desc_string(fn, toXYZD50);
817}
#define SkEndian_SwapBE16(n)
sk_sp< SkData > SkWriteICCProfile(const skcms_ICCProfile *profile, const char *desc)
static constexpr skcms_TransferFunction kLinear
bool skcms_TransferFunction_isHLGish(const skcms_TransferFunction *tf)
bool skcms_TransferFunction_isPQish(const skcms_TransferFunction *tf)
bool skcms_TransferFunction_isSRGBish(const skcms_TransferFunction *tf)