File indexing completed on 2024-12-22 04:15:56
0001 /* 0002 * SPDX-FileCopyrightText: 2022 L. E. Segovia <amy@amyspark.me> 0003 * SPDX-FileCopyrightText: 2024 Lucas Chollet <lucas.chollet@serenityos.org> 0004 * 0005 * SPDX-License-Identifier: GPL-2.0-or-later 0006 */ 0007 0008 #include <KoColorModelStandardIdsUtils.h> 0009 #include <KoColorSpace.h> 0010 #include <KoColorSpaceRegistry.h> 0011 #include <KoID.h> 0012 #include <kis_iterator_ng.h> 0013 0014 #include "kis_tiff_base_writer.h" 0015 #include "kis_tiff_converter.h" 0016 0017 KisTIFFBaseWriter::KisTIFFBaseWriter(TIFF *image, KisTIFFOptions *options) 0018 : m_image(image) 0019 , m_options(options) 0020 { 0021 } 0022 0023 bool KisTIFFBaseWriter::isBitDepthFloat(const KoID depth) 0024 { 0025 return depth == Float16BitsColorDepthID || depth == Float32BitsColorDepthID || depth == Float64BitsColorDepthID; 0026 } 0027 0028 bool KisTIFFBaseWriter::writeColorSpaceInformation(TIFF *image, 0029 const KoColorSpace *cs, 0030 uint16_t &color_type, 0031 uint16_t &sample_format, 0032 const KoColorSpace *&destColorSpace) 0033 { 0034 const KoID id = cs->colorModelId(); 0035 const KoID depth = cs->colorDepthId(); 0036 // destColorSpace should be reassigned to a proper color space to convert to 0037 // if the return value of this function is false 0038 destColorSpace = nullptr; 0039 0040 // sample_format and color_type should be assigned to the destination color 0041 // space, not /always/ the one we get here 0042 0043 if (id == RGBAColorModelID) { 0044 color_type = PHOTOMETRIC_RGB; 0045 if (isBitDepthFloat(depth)) { 0046 sample_format = SAMPLEFORMAT_IEEEFP; 0047 } 0048 return true; 0049 0050 } else if (id == CMYKAColorModelID) { 0051 color_type = PHOTOMETRIC_SEPARATED; 0052 TIFFSetField(image, TIFFTAG_INKSET, INKSET_CMYK); 0053 0054 if (isBitDepthFloat(depth)) { 0055 sample_format = SAMPLEFORMAT_IEEEFP; 0056 } 0057 return true; 0058 0059 } else if (id == LABAColorModelID) { 0060 color_type = PHOTOMETRIC_ICCLAB; 0061 0062 if (isBitDepthFloat(depth)) { 0063 sample_format = SAMPLEFORMAT_IEEEFP; 0064 } 0065 return true; 0066 0067 } else if (id == GrayAColorModelID) { 0068 color_type = PHOTOMETRIC_MINISBLACK; 0069 if (isBitDepthFloat(depth)) { 0070 sample_format = SAMPLEFORMAT_IEEEFP; 0071 } 0072 return true; 0073 } else if (id == YCbCrAColorModelID) { 0074 color_type = PHOTOMETRIC_YCBCR; 0075 if (isBitDepthFloat(depth)) { 0076 sample_format = SAMPLEFORMAT_IEEEFP; 0077 } 0078 return true; 0079 } else { 0080 color_type = PHOTOMETRIC_RGB; 0081 destColorSpace = 0082 KoColorSpaceRegistry::instance()->colorSpace(RGBAColorModelID.id(), 0083 depth.id(), 0084 KoColorSpaceRegistry::instance()->p709SRGBProfile()); 0085 if (isBitDepthFloat(depth)) { 0086 sample_format = SAMPLEFORMAT_IEEEFP; 0087 } 0088 return false; 0089 } 0090 } 0091 0092 bool KisTIFFBaseWriter::copyDataToStrips(KisHLineConstIteratorSP it, 0093 tdata_t buff, 0094 uint32_t depth, 0095 uint16_t sample_format, 0096 uint8_t nbcolorssamples, 0097 const std::array<quint8, 5> &poses) 0098 { 0099 if (depth == 32) { 0100 Q_ASSERT(sample_format == SAMPLEFORMAT_IEEEFP); 0101 float *dst = reinterpret_cast<float *>(buff); 0102 do { 0103 const float *d = reinterpret_cast<const float *>(it->oldRawData()); 0104 for (uint8_t i = 0; i < nbcolorssamples; i++) { 0105 *(dst++) = d[poses.at(i)]; 0106 } 0107 if (m_options->alpha) 0108 *(dst++) = d[poses.at(nbcolorssamples)]; 0109 } while (it->nextPixel()); 0110 return true; 0111 } else if (depth == 16) { 0112 if (sample_format == SAMPLEFORMAT_IEEEFP) { 0113 #ifdef HAVE_OPENEXR 0114 half *dst = reinterpret_cast<half *>(buff); 0115 do { 0116 const half *d = reinterpret_cast<const half *>(it->oldRawData()); 0117 for (uint8_t i = 0; i < nbcolorssamples; i++) { 0118 *(dst++) = d[poses.at(i)]; 0119 } 0120 if (m_options->alpha) 0121 *(dst++) = d[poses.at(nbcolorssamples)]; 0122 0123 } while (it->nextPixel()); 0124 return true; 0125 #endif 0126 } else { 0127 quint16 *dst = reinterpret_cast<quint16 *>(buff); 0128 do { 0129 const quint16 *d = reinterpret_cast<const quint16 *>(it->oldRawData()); 0130 for (uint8_t i = 0; i < nbcolorssamples; i++) { 0131 *(dst++) = d[poses.at(i)]; 0132 } 0133 if (m_options->alpha) 0134 *(dst++) = d[poses.at(nbcolorssamples)]; 0135 0136 } while (it->nextPixel()); 0137 return true; 0138 } 0139 } else if (depth == 8) { 0140 quint8 *dst = reinterpret_cast<quint8 *>(buff); 0141 do { 0142 const quint8 *d = it->oldRawData(); 0143 for (uint8_t i = 0; i < nbcolorssamples; i++) { 0144 *(dst++) = d[poses.at(i)]; 0145 } 0146 if (m_options->alpha) 0147 *(dst++) = d[poses.at(nbcolorssamples)]; 0148 0149 } while (it->nextPixel()); 0150 return true; 0151 } 0152 return false; 0153 }