Eigen::Matrix3f Chroma::calculate_chromatic_adaptation_transform(const Chroma::XYZ &from,
                                                                 const Chroma::XYZ &to,
                                                                 const std::vector<float> &adaptation=Chroma::BradfordTransform)
{
    Eigen::Vector3f src;
    src << from.X, from.Y, from.Z;
    Eigen::Vector3f dst;
    dst << to.X, to.Y, to.Z;
    Eigen::Matrix3f adapt_m(adaptation.data());
    Eigen::Array3f crd_s = adapt_m * src;
    Eigen::Array3f crd_d = adapt_m * dst;
    Eigen::Vector3f quot = crd_d / crd_s;
    Eigen::Matrix3f M = adapt_m.inverse() * quot.asDiagonal() * adapt_m;
    return M;
}