File indexing completed on 2024-05-19 05:31:34
0001 /* 0002 KWin - the KDE window manager 0003 This file is part of the KDE project. 0004 0005 SPDX-FileCopyrightText: 2022 Xaver Hugl <xaver.hugl@gmail.com> 0006 0007 SPDX-License-Identifier: GPL-2.0-or-later 0008 */ 0009 #include "colortransformation.h" 0010 #include "colorpipelinestage.h" 0011 0012 #include <lcms2.h> 0013 0014 #include "utils/common.h" 0015 0016 namespace KWin 0017 { 0018 0019 ColorTransformation::ColorTransformation(std::vector<std::unique_ptr<ColorPipelineStage>> &&stages) 0020 : m_pipeline(cmsPipelineAlloc(nullptr, 3, 3)) 0021 , m_stages(std::move(stages)) 0022 { 0023 if (!m_pipeline) { 0024 qCWarning(KWIN_CORE) << "Failed to allocate cmsPipeline!"; 0025 m_valid = false; 0026 return; 0027 } 0028 for (auto &stage : m_stages) { 0029 if (!cmsPipelineInsertStage(m_pipeline, cmsAT_END, stage->stage())) { 0030 qCWarning(KWIN_CORE) << "Failed to insert cmsPipeline stage!"; 0031 m_valid = false; 0032 return; 0033 } 0034 } 0035 } 0036 0037 ColorTransformation::~ColorTransformation() 0038 { 0039 if (m_pipeline) { 0040 cmsStage *last = nullptr; 0041 do { 0042 cmsPipelineUnlinkStage(m_pipeline, cmsAT_END, &last); 0043 } while (last); 0044 cmsPipelineFree(m_pipeline); 0045 } 0046 } 0047 0048 void ColorTransformation::append(ColorTransformation *transformation) 0049 { 0050 for (auto &stage : transformation->m_stages) { 0051 auto dup = stage->dup(); 0052 if (!cmsPipelineInsertStage(m_pipeline, cmsAT_END, dup->stage())) { 0053 qCWarning(KWIN_CORE) << "Failed to insert cmsPipeline stage!"; 0054 m_valid = false; 0055 return; 0056 } 0057 m_stages.push_back(std::move(dup)); 0058 } 0059 } 0060 0061 bool ColorTransformation::valid() const 0062 { 0063 return m_valid; 0064 } 0065 0066 std::tuple<uint16_t, uint16_t, uint16_t> ColorTransformation::transform(uint16_t r, uint16_t g, uint16_t b) const 0067 { 0068 const uint16_t in[3] = {r, g, b}; 0069 uint16_t out[3] = {0, 0, 0}; 0070 cmsPipelineEval16(in, out, m_pipeline); 0071 return {out[0], out[1], out[2]}; 0072 } 0073 0074 QVector3D ColorTransformation::transform(QVector3D in) const 0075 { 0076 QVector3D ret; 0077 cmsPipelineEvalFloat(&in[0], &ret[0], m_pipeline); 0078 return ret; 0079 } 0080 0081 std::unique_ptr<ColorTransformation> ColorTransformation::createScalingTransform(const QVector3D &scale) 0082 { 0083 std::array<double, 3> curveParams = {1.0, scale.x(), 0.0}; 0084 auto r = cmsBuildParametricToneCurve(nullptr, 2, curveParams.data()); 0085 curveParams = {1.0, scale.y(), 0.0}; 0086 auto g = cmsBuildParametricToneCurve(nullptr, 2, curveParams.data()); 0087 curveParams = {1.0, scale.z(), 0.0}; 0088 auto b = cmsBuildParametricToneCurve(nullptr, 2, curveParams.data()); 0089 if (!r || !g || !b) { 0090 qCWarning(KWIN_CORE) << "Failed to build tone curves"; 0091 return nullptr; 0092 } 0093 const std::array curves = {r, g, b}; 0094 const auto stage = cmsStageAllocToneCurves(nullptr, 3, curves.data()); 0095 if (!stage) { 0096 qCWarning(KWIN_CORE) << "Failed to allocate tone curves"; 0097 return nullptr; 0098 } 0099 std::vector<std::unique_ptr<ColorPipelineStage>> stages; 0100 stages.push_back(std::make_unique<ColorPipelineStage>(stage)); 0101 auto transform = std::make_unique<ColorTransformation>(std::move(stages)); 0102 if (!transform->valid()) { 0103 return nullptr; 0104 } 0105 return transform; 0106 } 0107 }