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 }