File indexing completed on 2024-04-28 15:25:45

0001 /*
0002     SPDX-FileCopyrightText: 2023 Mirco Miranda <mircomir@outlook.com>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "scanlineconverter_p.h"
0008 #include <cstring>
0009 
0010 ScanLineConverter::ScanLineConverter(const QImage::Format &targetFormat)
0011     : _targetFormat(targetFormat)
0012 {
0013 }
0014 
0015 ScanLineConverter::ScanLineConverter(const ScanLineConverter &other)
0016     : _targetFormat(other._targetFormat)
0017     , _colorSpace(other._colorSpace)
0018 {
0019 }
0020 
0021 ScanLineConverter &ScanLineConverter::operator=(const ScanLineConverter &other)
0022 {
0023     this->_targetFormat = other._targetFormat;
0024     this->_colorSpace = other._colorSpace;
0025     return (*this);
0026 }
0027 
0028 QImage::Format ScanLineConverter::targetFormat() const
0029 {
0030     return _targetFormat;
0031 }
0032 
0033 void ScanLineConverter::setTargetColorSpace(const QColorSpace &colorSpace)
0034 {
0035     _colorSpace = colorSpace;
0036 }
0037 
0038 QColorSpace ScanLineConverter::targetColorSpace() const
0039 {
0040     return _colorSpace;
0041 }
0042 
0043 const uchar *ScanLineConverter::convertedScanLine(const QImage &image, qint32 y)
0044 {
0045     auto colorSpaceConversion = isColorSpaceConversionNeeded(image, _colorSpace);
0046     if (image.format() == _targetFormat && !colorSpaceConversion) {
0047         return image.constScanLine(y);
0048     }
0049     if (image.width() != _tmpBuffer.width() || image.format() != _tmpBuffer.format()) {
0050         _tmpBuffer = QImage(image.width(), 1, image.format());
0051     }
0052     if (_tmpBuffer.isNull()) {
0053         return nullptr;
0054     }
0055     std::memcpy(_tmpBuffer.bits(), image.constScanLine(y), std::min(_tmpBuffer.bytesPerLine(), image.bytesPerLine()));
0056     if (colorSpaceConversion) {
0057         _tmpBuffer.setColorSpace(image.colorSpace());
0058         _tmpBuffer.convertToColorSpace(_colorSpace);
0059     }
0060     _convBuffer = _tmpBuffer.convertToFormat(_targetFormat);
0061     if (_convBuffer.isNull()) {
0062         return nullptr;
0063     }
0064     return _convBuffer.constBits();
0065 }
0066 
0067 qsizetype ScanLineConverter::bytesPerLine() const
0068 {
0069     if (_convBuffer.isNull()) {
0070         return 0;
0071     }
0072     return _convBuffer.bytesPerLine();
0073 }
0074 
0075 bool ScanLineConverter::isColorSpaceConversionNeeded(const QImage &image, const QColorSpace &targetColorSpace) const
0076 {
0077     if (image.depth() < 24) { // RGB 8 bit or grater only
0078         return false;
0079     }
0080     auto sourceColorSpace = image.colorSpace();
0081     if (!sourceColorSpace.isValid() || !targetColorSpace.isValid()) {
0082         return false;
0083     }
0084 
0085     auto stf = sourceColorSpace.transferFunction();
0086     auto spr = sourceColorSpace.primaries();
0087     auto ttf = targetColorSpace.transferFunction();
0088     auto tpr = targetColorSpace.primaries();
0089     // clang-format off
0090     if (stf == QColorSpace::TransferFunction::Custom ||
0091         ttf == QColorSpace::TransferFunction::Custom ||
0092         spr == QColorSpace::Primaries::Custom ||
0093         tpr == QColorSpace::Primaries::Custom) {
0094         return true;
0095     }
0096     // clang-format on
0097     if (stf == ttf && spr == tpr) {
0098         return false;
0099     }
0100     return true;
0101 }