File indexing completed on 2024-04-28 03:54:46

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     , _defaultColorSpace(other._defaultColorSpace)
0019 {
0020 }
0021 
0022 ScanLineConverter &ScanLineConverter::operator=(const ScanLineConverter &other)
0023 {
0024     _targetFormat = other._targetFormat;
0025     _colorSpace = other._colorSpace;
0026     _defaultColorSpace = other._defaultColorSpace;
0027     return (*this);
0028 }
0029 
0030 QImage::Format ScanLineConverter::targetFormat() const
0031 {
0032     return _targetFormat;
0033 }
0034 
0035 void ScanLineConverter::setTargetColorSpace(const QColorSpace &colorSpace)
0036 {
0037     _colorSpace = colorSpace;
0038 }
0039 
0040 QColorSpace ScanLineConverter::targetColorSpace() const
0041 {
0042     return _colorSpace;
0043 }
0044 
0045 void ScanLineConverter::setDefaultSourceColorSpace(const QColorSpace &colorSpace)
0046 {
0047     _defaultColorSpace = colorSpace;
0048 }
0049 
0050 QColorSpace ScanLineConverter::defaultSourceColorSpace() const
0051 {
0052     return _defaultColorSpace;
0053 }
0054 
0055 const uchar *ScanLineConverter::convertedScanLine(const QImage &image, qint32 y)
0056 {
0057     auto colorSpaceConversion = isColorSpaceConversionNeeded(image);
0058     if (image.format() == _targetFormat && !colorSpaceConversion) {
0059         return image.constScanLine(y);
0060     }
0061     if (image.width() != _tmpBuffer.width() || image.format() != _tmpBuffer.format()) {
0062         _tmpBuffer = QImage(image.width(), 1, image.format());
0063         _tmpBuffer.setColorTable(image.colorTable());
0064     }
0065     if (_tmpBuffer.isNull()) {
0066         return nullptr;
0067     }
0068     std::memcpy(_tmpBuffer.bits(), image.constScanLine(y), std::min(_tmpBuffer.bytesPerLine(), image.bytesPerLine()));
0069     auto tmp = _tmpBuffer;
0070     if (colorSpaceConversion) {
0071         auto cs = image.colorSpace();
0072         if (!cs.isValid()) {
0073             cs = _defaultColorSpace;
0074         }
0075         if (tmp.depth() < 24) {
0076             tmp.convertTo(tmp.hasAlphaChannel() ? QImage::Format_ARGB32 : QImage::Format_RGB32);
0077         }
0078         tmp.setColorSpace(cs);
0079         tmp.convertToColorSpace(_colorSpace);
0080     }
0081 
0082     /*
0083      * Work Around for wrong RGBA64 -> 16FPx4/32FPx4 conversion on Intel architecture.
0084      * Luckily convertTo() works fine with 16FPx4 images so I can use it instead convertToFormat().
0085      * See also: https://bugreports.qt.io/browse/QTBUG-120614
0086      */
0087     tmp.convertTo(_targetFormat);
0088     _convBuffer = tmp;
0089 
0090     if (_convBuffer.isNull()) {
0091         return nullptr;
0092     }
0093     return _convBuffer.constBits();
0094 }
0095 
0096 qsizetype ScanLineConverter::bytesPerLine() const
0097 {
0098     if (_convBuffer.isNull()) {
0099         return 0;
0100     }
0101     return _convBuffer.bytesPerLine();
0102 }
0103 
0104 bool ScanLineConverter::isColorSpaceConversionNeeded(const QImage &image, const QColorSpace &targetColorSpace, const QColorSpace &defaultColorSpace)
0105 {
0106     auto sourceColorSpace = image.colorSpace();
0107     if (!sourceColorSpace.isValid()) {
0108         sourceColorSpace = defaultColorSpace;
0109     }
0110     if (!sourceColorSpace.isValid() || !targetColorSpace.isValid()) {
0111         return false;
0112     }
0113 
0114     auto stf = sourceColorSpace.transferFunction();
0115     auto spr = sourceColorSpace.primaries();
0116     auto ttf = targetColorSpace.transferFunction();
0117     auto tpr = targetColorSpace.primaries();
0118     // clang-format off
0119     if (stf == QColorSpace::TransferFunction::Custom ||
0120         ttf == QColorSpace::TransferFunction::Custom ||
0121         spr == QColorSpace::Primaries::Custom ||
0122         tpr == QColorSpace::Primaries::Custom) {
0123         return true;
0124     }
0125     // clang-format on
0126     if (stf == ttf && spr == tpr) {
0127         return false;
0128     }
0129     return true;
0130 }