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 }