File indexing completed on 2025-01-19 03:54:50

0001 /* ============================================================
0002  *
0003  * This file is a part of digiKam project
0004  * https://www.digikam.org
0005  *
0006  * Date        : 2005-06-14
0007  * Description : digiKam 8/16 bits image management API.
0008  *               QPixmap accessors.
0009  *
0010  * SPDX-FileCopyrightText: 2005-2024 by Gilles Caulier <caulier dot gilles at gmail dot com>
0011  * SPDX-FileCopyrightText: 2006-2013 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de>
0012  *
0013  * SPDX-License-Identifier: GPL-2.0-or-later
0014  *
0015  * ============================================================ */
0016 
0017 #include "dimg_p.h"
0018 
0019 namespace Digikam
0020 {
0021 
0022 class Q_DECL_HIDDEN PixmapPaintEngineDetector
0023 {
0024 public:
0025 
0026     PixmapPaintEngineDetector()
0027         : m_isRaster(detectRasterFromPixmap())
0028     {
0029     }
0030 
0031     bool isRaster() const
0032     {
0033         return m_isRaster;
0034     }
0035 
0036 private:
0037 
0038     static bool detectRasterFromPixmap()
0039     {
0040         QPixmap pix(1, 1);
0041         QPainter p(&pix);
0042         return (p.paintEngine() && (p.paintEngine()->type() == QPaintEngine::Raster));
0043     }
0044 
0045     const bool m_isRaster;
0046 };
0047 
0048 Q_GLOBAL_STATIC(PixmapPaintEngineDetector, pixmapPaintEngineDetector)
0049 
0050 // --------------------------------------------------------------------------------------
0051 
0052 QPixmap DImg::convertToPixmap() const
0053 {
0054     if (isNull())
0055     {
0056         return QPixmap();
0057     }
0058 
0059     if (sixteenBit())
0060     {
0061         // make faster...
0062 
0063         return QPixmap::fromImage(copyQImage(0, 0, width(), height()));
0064     }
0065 
0066     if (QSysInfo::ByteOrder == QSysInfo::BigEndian)
0067     {
0068         QImage img(width(), height(), hasAlpha() ? QImage::Format_ARGB32 : QImage::Format_RGB32);
0069 
0070         uchar* sptr = bits();
0071         uint*  dptr = reinterpret_cast<uint*>(img.bits());
0072         uint dim    = width() * height();
0073 
0074         for (uint i = 0 ; i < dim ; ++i)
0075         {
0076             *dptr++ = qRgba(sptr[2], sptr[1], sptr[0], sptr[3]);
0077             sptr   += 4;
0078         }
0079 
0080         // alpha channel is auto-detected during QImage->QPixmap conversion
0081 
0082         return QPixmap::fromImage(img);
0083     }
0084     else
0085     {
0086         // This is a temporary image operating on the DImg buffer
0087 
0088         QImage img(bits(), width(), height(), hasAlpha() ? QImage::Format_ARGB32 : QImage::Format_RGB32);
0089 
0090         // For paint engines which base the QPixmap internally on a QImage, we must use a persistent QImage
0091 
0092         if (pixmapPaintEngineDetector->isRaster())
0093         {
0094             img = img.copy();
0095         }
0096 
0097         // alpha channel is auto-detected during QImage->QPixmap conversion
0098 
0099         return QPixmap::fromImage(img);
0100     }
0101 }
0102 
0103 QPixmap DImg::convertToPixmap(IccTransform& monitorICCtrans) const
0104 {
0105     if (isNull())
0106     {
0107         return QPixmap();
0108     }
0109 
0110     if (monitorICCtrans.outputProfile().isNull())
0111     {
0112         return convertToPixmap();
0113     }
0114 
0115     DImg img = copy();
0116     monitorICCtrans.apply(img);
0117 
0118     return (img.convertToPixmap());
0119 }
0120 
0121 QImage DImg::pureColorMask(ExposureSettingsContainer* const expoSettings) const
0122 {
0123     if (isNull() || (!expoSettings->underExposureIndicator && !expoSettings->overExposureIndicator))
0124     {
0125         return QImage();
0126     }
0127 
0128     QImage img(size(), QImage::Format_ARGB32);
0129     img.fill(0x00000000);      // Full transparent.
0130 
0131     // NOTE: Qt4 do not provide anymore QImage::setAlphaChannel() because
0132     // alpha channel is auto-detected during QImage->QPixmap conversion
0133 
0134     uchar* bits = img.bits();
0135 
0136     // NOTE: Using DImgScale before to compute Mask clamp to 65534 | 254. Why ?
0137 
0138     int    max  = lround(sixteenBit() ? 65535.0 - (65535.0 * expoSettings->overExposurePercent  / 100.0)
0139                          : 255.0   - (255.0   * expoSettings->overExposurePercent  / 100.0));
0140     int    min  = lround(sixteenBit() ? 0.0     + (65535.0 * expoSettings->underExposurePercent / 100.0)
0141                          : 0.0     + (255.0   * expoSettings->underExposurePercent / 100.0));
0142 
0143     // --------------------------------------------------------
0144 
0145     // caching
0146 
0147     int u_red   = expoSettings->underExposureColor.red();
0148     int u_green = expoSettings->underExposureColor.green();
0149     int u_blue  = expoSettings->underExposureColor.blue();
0150 
0151     int o_red   = expoSettings->overExposureColor.red();
0152     int o_green = expoSettings->overExposureColor.green();
0153     int o_blue  = expoSettings->overExposureColor.blue();
0154 
0155     bool under  = expoSettings->underExposureIndicator;
0156     bool over   = expoSettings->overExposureIndicator;
0157     bool pure   = expoSettings->exposureIndicatorMode;
0158 
0159     // --------------------------------------------------------
0160 
0161     uint   dim   = m_priv->width * m_priv->height;
0162     uchar* dptr  = bits;
0163     int    s_blue, s_green, s_red;
0164     bool   match = false;
0165 
0166     if (sixteenBit())
0167     {
0168         unsigned short* sptr = reinterpret_cast<unsigned short*>(m_priv->data);
0169 
0170         for (uint i = 0 ; i < dim ; ++i)
0171         {
0172             s_blue  = *sptr++;
0173             s_green = *sptr++;
0174             s_red   = *sptr++;
0175             sptr++;
0176             match = pure ? (s_red <= min) && (s_green <= min) && (s_blue <= min)
0177                          : (s_red <= min) || (s_green <= min) || (s_blue <= min);
0178 
0179             if (under && match)
0180             {
0181                 if (QSysInfo::ByteOrder == QSysInfo::BigEndian)
0182                 {
0183                     dptr[0] = 0xFF;
0184                     dptr[1] = u_red;
0185                     dptr[2] = u_green;
0186                     dptr[3] = u_blue;
0187                 }
0188                 else
0189                 {
0190                     dptr[0] = u_blue;
0191                     dptr[1] = u_green;
0192                     dptr[2] = u_red;
0193                     dptr[3] = 0xFF;
0194                 }
0195             }
0196 
0197             match = pure ? (s_red >= max) && (s_green >= max) && (s_blue >= max)
0198                          : (s_red >= max) || (s_green >= max) || (s_blue >= max);
0199 
0200             if (over && match)
0201             {
0202                 if (QSysInfo::ByteOrder == QSysInfo::BigEndian)
0203                 {
0204                     dptr[0] = 0xFF;
0205                     dptr[1] = o_red;
0206                     dptr[2] = o_green;
0207                     dptr[3] = o_blue;
0208                 }
0209                 else
0210                 {
0211                     dptr[0] = o_blue;
0212                     dptr[1] = o_green;
0213                     dptr[2] = o_red;
0214                     dptr[3] = 0xFF;
0215                 }
0216             }
0217 
0218             dptr += 4;
0219         }
0220     }
0221     else
0222     {
0223         uchar* sptr = m_priv->data;
0224 
0225         for (uint i = 0 ; i < dim ; ++i)
0226         {
0227             s_blue  = *sptr++;
0228             s_green = *sptr++;
0229             s_red   = *sptr++;
0230             sptr++;
0231             match = pure ? (s_red <= min) && (s_green <= min) && (s_blue <= min)
0232                          : (s_red <= min) || (s_green <= min) || (s_blue <= min);
0233 
0234             if (under && match)
0235             {
0236                 if (QSysInfo::ByteOrder == QSysInfo::BigEndian)
0237                 {
0238                     dptr[0] = 0xFF;
0239                     dptr[1] = u_red;
0240                     dptr[2] = u_green;
0241                     dptr[3] = u_blue;
0242                 }
0243                 else
0244                 {
0245                     dptr[0] = u_blue;
0246                     dptr[1] = u_green;
0247                     dptr[2] = u_red;
0248                     dptr[3] = 0xFF;
0249                 }
0250             }
0251 
0252             match = pure ? (s_red >= max) && (s_green >= max) && (s_blue >= max)
0253                          : (s_red >= max) || (s_green >= max) || (s_blue >= max);
0254 
0255             if (over && match)
0256             {
0257                 if (QSysInfo::ByteOrder == QSysInfo::BigEndian)
0258                 {
0259                     dptr[0] = 0xFF;
0260                     dptr[1] = o_red;
0261                     dptr[2] = o_green;
0262                     dptr[3] = o_blue;
0263                 }
0264                 else
0265                 {
0266                     dptr[0] = o_blue;
0267                     dptr[1] = o_green;
0268                     dptr[2] = o_red;
0269                     dptr[3] = 0xFF;
0270                 }
0271             }
0272 
0273             dptr += 4;
0274         }
0275     }
0276 
0277     return img;
0278 }
0279 
0280 } // namespace Digikam