mirror of
https://invent.kde.org/frameworks/kimageformats.git
synced 2025-07-18 03:54:18 -04:00
131 lines
3.7 KiB
C++
131 lines
3.7 KiB
C++
/*
|
|
SPDX-FileCopyrightText: 2023 Mirco Miranda <mircomir@outlook.com>
|
|
|
|
SPDX-License-Identifier: LGPL-2.0-or-later
|
|
*/
|
|
|
|
#include "scanlineconverter_p.h"
|
|
#include <cstring>
|
|
|
|
ScanLineConverter::ScanLineConverter(const QImage::Format &targetFormat)
|
|
: _targetFormat(targetFormat)
|
|
{
|
|
}
|
|
|
|
ScanLineConverter::ScanLineConverter(const ScanLineConverter &other)
|
|
: _targetFormat(other._targetFormat)
|
|
, _colorSpace(other._colorSpace)
|
|
, _defaultColorSpace(other._defaultColorSpace)
|
|
{
|
|
}
|
|
|
|
ScanLineConverter &ScanLineConverter::operator=(const ScanLineConverter &other)
|
|
{
|
|
_targetFormat = other._targetFormat;
|
|
_colorSpace = other._colorSpace;
|
|
_defaultColorSpace = other._defaultColorSpace;
|
|
return (*this);
|
|
}
|
|
|
|
QImage::Format ScanLineConverter::targetFormat() const
|
|
{
|
|
return _targetFormat;
|
|
}
|
|
|
|
void ScanLineConverter::setTargetColorSpace(const QColorSpace &colorSpace)
|
|
{
|
|
_colorSpace = colorSpace;
|
|
}
|
|
|
|
QColorSpace ScanLineConverter::targetColorSpace() const
|
|
{
|
|
return _colorSpace;
|
|
}
|
|
|
|
void ScanLineConverter::setDefaultSourceColorSpace(const QColorSpace &colorSpace)
|
|
{
|
|
_defaultColorSpace = colorSpace;
|
|
}
|
|
|
|
QColorSpace ScanLineConverter::defaultSourceColorSpace() const
|
|
{
|
|
return _defaultColorSpace;
|
|
}
|
|
|
|
const uchar *ScanLineConverter::convertedScanLine(const QImage &image, qint32 y)
|
|
{
|
|
auto colorSpaceConversion = isColorSpaceConversionNeeded(image);
|
|
if (image.format() == _targetFormat && !colorSpaceConversion) {
|
|
return image.constScanLine(y);
|
|
}
|
|
if (image.width() != _tmpBuffer.width() || image.format() != _tmpBuffer.format()) {
|
|
_tmpBuffer = QImage(image.width(), 1, image.format());
|
|
_tmpBuffer.setColorTable(image.colorTable());
|
|
}
|
|
if (_tmpBuffer.isNull()) {
|
|
return nullptr;
|
|
}
|
|
std::memcpy(_tmpBuffer.bits(), image.constScanLine(y), std::min(_tmpBuffer.bytesPerLine(), image.bytesPerLine()));
|
|
auto tmp = _tmpBuffer;
|
|
if (colorSpaceConversion) {
|
|
auto cs = image.colorSpace();
|
|
if (!cs.isValid()) {
|
|
cs = _defaultColorSpace;
|
|
}
|
|
if (tmp.depth() < 24) {
|
|
tmp.convertTo(tmp.hasAlphaChannel() ? QImage::Format_ARGB32 : QImage::Format_RGB32);
|
|
}
|
|
tmp.setColorSpace(cs);
|
|
tmp.convertToColorSpace(_colorSpace);
|
|
}
|
|
|
|
/*
|
|
* Work Around for wrong RGBA64 -> 16FPx4/32FPx4 conversion on Intel architecture.
|
|
* Luckily convertTo() works fine with 16FPx4 images so I can use it instead convertToFormat().
|
|
* See also: https://bugreports.qt.io/browse/QTBUG-120614
|
|
*/
|
|
tmp.convertTo(_targetFormat);
|
|
_convBuffer = tmp;
|
|
|
|
if (_convBuffer.isNull()) {
|
|
return nullptr;
|
|
}
|
|
return _convBuffer.constBits();
|
|
}
|
|
|
|
qsizetype ScanLineConverter::bytesPerLine() const
|
|
{
|
|
if (_convBuffer.isNull()) {
|
|
return 0;
|
|
}
|
|
return _convBuffer.bytesPerLine();
|
|
}
|
|
|
|
bool ScanLineConverter::isColorSpaceConversionNeeded(const QImage &image, const QColorSpace &targetColorSpace, const QColorSpace &defaultColorSpace)
|
|
{
|
|
auto sourceColorSpace = image.colorSpace();
|
|
if (!sourceColorSpace.isValid()) {
|
|
sourceColorSpace = defaultColorSpace;
|
|
}
|
|
if (!sourceColorSpace.isValid() || !targetColorSpace.isValid()) {
|
|
return false;
|
|
}
|
|
|
|
auto stf = sourceColorSpace.transferFunction();
|
|
auto spr = sourceColorSpace.primaries();
|
|
auto ttf = targetColorSpace.transferFunction();
|
|
auto tpr = targetColorSpace.primaries();
|
|
// clang-format off
|
|
if (stf == QColorSpace::TransferFunction::Custom ||
|
|
ttf == QColorSpace::TransferFunction::Custom ||
|
|
spr == QColorSpace::Primaries::Custom ||
|
|
tpr == QColorSpace::Primaries::Custom) {
|
|
return true;
|
|
}
|
|
// clang-format on
|
|
if (stf == ttf && spr == tpr) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|