File indexing completed on 2024-12-22 04:13:04

0001 /*
0002  * This file is part of the KDE project
0003  *
0004  * SPDX-FileCopyrightText: 2019 Carl Olsson <carl.olsson@gmail.com>
0005  *
0006  *  SPDX-License-Identifier: GPL-2.0-or-later
0007  */
0008 
0009 #include "KisDitherUtil.h"
0010 
0011 #include <kis_filter_configuration.h>
0012 #include <kis_random_generator.h>
0013 #include <KisResourcesInterface.h>
0014 
0015 KisDitherUtil::KisDitherUtil()
0016     : m_thresholdMode(ThresholdMode::Pattern), m_patternValueMode(PatternValueMode::Auto)
0017     , m_noiseSeed(0), m_patternUseAlpha(false), m_spread(1.0)
0018 {
0019 }
0020 
0021 void KisDitherUtil::setThresholdMode(const ThresholdMode thresholdMode)
0022 {
0023     m_thresholdMode = thresholdMode;
0024 }
0025 
0026 void KisDitherUtil::setPattern(const QString &md5sum, const QString &patternName, const PatternValueMode valueMode, KisResourcesInterfaceSP resourcesInterface)
0027 {
0028     m_patternValueMode = valueMode;
0029 
0030     auto source = resourcesInterface->source<KoPattern>(ResourceType::Patterns);
0031     m_pattern = source.bestMatch(md5sum, "", patternName);
0032 
0033     if (m_pattern && m_thresholdMode == ThresholdMode::Pattern && m_patternValueMode == PatternValueMode::Auto) {
0034         // Automatically pick between lightness-based and alpha-based patterns by whichever has maximum range
0035         qreal lightnessMin = 1.0, lightnessMax = 0.0;
0036         qreal alphaMin = 1.0, alphaMax = 0.0;
0037         const QImage &image = m_pattern->pattern();
0038         for (int y = 0; y < image.height(); ++y) {
0039             for (int x = 0; x < image.width(); ++x) {
0040                 const QColor pixel = image.pixelColor(x, y);
0041                 lightnessMin = std::min(lightnessMin, pixel.lightnessF());
0042                 lightnessMax = std::max(lightnessMax, pixel.lightnessF());
0043                 alphaMin = std::min(alphaMin, pixel.alphaF());
0044                 alphaMax = std::max(alphaMax, pixel.alphaF());
0045             }
0046         }
0047         m_patternUseAlpha = (alphaMax - alphaMin > lightnessMax - lightnessMin);
0048     }
0049     else {
0050         m_patternUseAlpha = (m_patternValueMode == PatternValueMode::Alpha);
0051     }
0052 }
0053 
0054 void KisDitherUtil::setNoiseSeed(const quint64 &noiseSeed)
0055 {
0056     m_noiseSeed = noiseSeed;
0057 }
0058 
0059 void KisDitherUtil::setSpread(const qreal &spread)
0060 {
0061     m_spread = spread;
0062 }
0063 
0064 qreal KisDitherUtil::threshold(const QPoint &pos)
0065 {
0066     qreal threshold;
0067     if (m_thresholdMode == ThresholdMode::Pattern && m_pattern) {
0068         const QImage &image = m_pattern->pattern();
0069         const QColor color = image.pixelColor(pos.x() % image.width(), pos.y() % image.height());
0070         threshold = (m_patternUseAlpha ? color.alphaF() : color.lightnessF());
0071     }
0072     else if (m_thresholdMode == ThresholdMode::Noise) {
0073         KisRandomGenerator random(m_noiseSeed);
0074         threshold = random.doubleRandomAt(pos.x(), pos.y());
0075     }
0076     else threshold = 0.5;
0077 
0078     return 0.5 - (m_spread / 2.0) + threshold * m_spread;
0079 }
0080 
0081 void KisDitherUtil::setConfiguration(const KisFilterConfiguration &config, const QString &prefix)
0082 {
0083     setThresholdMode(ThresholdMode(config.getInt(prefix + "thresholdMode")));
0084     setPattern(config.getString(prefix + "md5sum"), config.getString(prefix + "pattern"), PatternValueMode(config.getInt(prefix + "patternValueMode")), config.resourcesInterface());
0085     setNoiseSeed(quint64(config.getInt(prefix + "noiseSeed")));
0086     setSpread(config.getDouble(prefix + "spread"));
0087 }