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 }