Files
PDF4QT/Pdf4QtLib/sources/pdfcolorconvertor.cpp
2023-11-18 18:52:18 +01:00

211 lines
5.7 KiB
C++

// Copyright (C) 2023 Jakub Melka
//
// This file is part of PDF4QT.
//
// PDF4QT is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// with the written consent of the copyright owner, any later version.
//
// PDF4QT is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with PDF4QT. If not, see <https://www.gnu.org/licenses/>.
#include "pdfcolorconvertor.h"
#include "pdfimageconversion.h"
#include "pdfutils.h"
namespace pdf
{
PDFColorConvertor::PDFColorConvertor()
{
calculateSigmoidParams();
}
bool PDFColorConvertor::isActive() const
{
return m_mode != Mode::Normal;
}
void PDFColorConvertor::setMode(Mode mode)
{
m_mode = mode;
}
QColor PDFColorConvertor::convert(QColor color, bool background, bool foreground) const
{
switch (m_mode)
{
case Mode::Normal:
return color;
case Mode::InvertedColors:
return invertColor(color);
case Mode::Grayscale:
{
int gray = qGray(color.red(), color.green(), color.blue());
return QColor(gray, gray, gray, color.alpha());
}
case Mode::HighContrast:
{
const float lightness = color.lightnessF();
const float adjustedLightness = correctLigthnessBySigmoidFunction(lightness);
QColor hslColor = color.toHsl();
hslColor.setHslF(hslColor.hueF(), hslColor.saturationF(), adjustedLightness, color.alphaF());
return hslColor.toRgb();
}
case Mode::Bitonal:
{
const int lightness = color.lightness();
QColor bitonalColor = (lightness >= m_bitonalThreshold) ? QColor(Qt::white) : QColor(Qt::black);
bitonalColor.setAlpha(bitonalColor.alpha());
return bitonalColor;
}
case Mode::CustomColors:
{
if (background)
{
return m_backgroundColor;
}
if (foreground)
{
return m_foregroundColor;
}
const float lightness = color.lightnessF();
QColor hslColor = m_foregroundColor;
hslColor.setHslF(hslColor.hueF(), hslColor.saturationF(), lightness, color.alphaF());
return hslColor.toRgb();
}
default:
Q_ASSERT(false);
break;
}
return color;
}
QImage PDFColorConvertor::convert(QImage image) const
{
switch (m_mode)
{
case Mode::Normal:
return image;
case Mode::InvertedColors:
{
image.invertPixels(QImage::InvertRgb);
return image;
}
case Mode::Grayscale:
{
QImage alpha = image.convertedTo(QImage::Format_Alpha8);
QImage grayscaleImage = image.convertedTo(QImage::Format_Grayscale8);
QImage resultImage = grayscaleImage;
resultImage = resultImage.convertedTo(QImage::Format_ARGB32);
resultImage.setAlphaChannel(std::move(alpha));
return resultImage;
}
case Mode::Bitonal:
{
PDFImageConversion imageConversion;
imageConversion.setConversionMethod(PDFImageConversion::ConversionMethod::Automatic);
imageConversion.setImage(image);
if (imageConversion.convert())
{
return imageConversion.getConvertedImage();
}
return image;
}
case Mode::HighContrast:
case Mode::CustomColors:
{
for (int row = 0; row < image.height(); ++row)
{
for (int column = 0; column < image.width(); ++column)
{
QColor color = image.pixelColor(column, row);
QColor adjustedColor = convert(color, false, false);
image.setPixelColor(column, row, adjustedColor);
}
}
return image;
}
default:
Q_ASSERT(false);
break;
}
return image;
}
void PDFColorConvertor::setHighContrastBrightnessFactor(float factor)
{
m_sigmoidParamC = factor;
calculateSigmoidParams();
}
float PDFColorConvertor::correctLigthnessBySigmoidFunction(float lightness) const
{
const float adjustedLightness = sigmoidFunction(lightness);
const float normalizedLightness = (adjustedLightness - m_sigmoidParamC_Black) / m_sigmoidParamC_Range;
return qBound(0.0f, normalizedLightness, 1.0f);
}
float PDFColorConvertor::sigmoidFunction(float value) const
{
return 1.0f / (1.0f + std::expf(-m_sigmoidParamC * (value - 0.5f)));
}
float PDFColorConvertor::sigmoidParamC_Black() const
{
return sigmoidFunction(0.0);
}
float PDFColorConvertor::sigmoidParamC_White() const
{
return sigmoidFunction(1.0);
}
float PDFColorConvertor::sigmoidParamC_Range() const
{
return sigmoidParamC_White() - sigmoidParamC_Black();
}
void PDFColorConvertor::calculateSigmoidParams()
{
m_sigmoidParamC_Black = sigmoidParamC_Black();
m_sigmoidParamC_White = sigmoidParamC_White();
m_sigmoidParamC_Range = sigmoidParamC_Range();
}
int PDFColorConvertor::getBitonalThreshold() const
{
return m_bitonalThreshold;
}
void PDFColorConvertor::setBitonalThreshold(int newBitonalThreshold)
{
m_bitonalThreshold = newBitonalThreshold;
}
} // namespace pdf