File indexing completed on 2024-05-12 15:59:30

0001 /*
0002  *  SPDX-FileCopyrightText: 2004 Boudewijn Rempt <boud@valdyas.org>
0003  *  SPDX-FileCopyrightText: 2020 L. E. Segovia <amy@amyspark.me>
0004  *
0005  * SPDX-License-Identifier: LGPL-2.0-or-later
0006 */
0007 #ifndef KOCHANNELINFO_H_
0008 #define KOCHANNELINFO_H_
0009 
0010 #include <limits>
0011 
0012 #include <QColor>
0013 #include <QString>
0014 #include <QList>
0015 
0016 /**
0017  * This class gives some basic information about a channel,
0018  * that is, one of the components that makes up a particular
0019  * pixel.
0020  */
0021 class KoChannelInfo
0022 {
0023 public:
0024     /**
0025      * Used to represent a min and max range.
0026      */
0027     struct DoubleRange
0028     {
0029         public:
0030             double minVal, maxVal;
0031         public:
0032             /// creates an invalid range of 0,0
0033             DoubleRange(void) : minVal(0), maxVal(0) { }
0034             /// creates
0035             DoubleRange(qreal _minVal, qreal _maxVal) : minVal(_minVal), maxVal(_maxVal) { Q_ASSERT(minVal <= maxVal); }
0036             /// true if this range is usable
0037             bool isValid(void) const { return minVal < maxVal; }
0038     };
0039 public:
0040     /// enum to define the type of the channel
0041     enum enumChannelType {
0042         COLOR, ///< The channel represents a color
0043         ALPHA ///< The channel represents the opacity of a pixel
0044         //SUBSTANCE, ///< The channel represents a real-world substance like pigments or medium
0045         //SUBSTRATE ///< The channel represents a real-world painting substrate like a canvas
0046     };
0047     /// enum to define the value of the channel
0048     enum enumChannelValueType {
0049         UINT8, ///< use this for an unsigned integer 8bits channel
0050         UINT16, ///< use this for an integer 16bits channel
0051         UINT32, ///< use this for an unsigned integer 21bits channel
0052         FLOAT16, ///< use this for a float 16bits channel
0053         FLOAT32, ///< use this for a float 32bits channel
0054         FLOAT64, ///< use this for a float 64bits channel
0055         INT8, ///< use this for an integer 8bits channel
0056         INT16, ///< use this for an integer 16bits channel
0057         OTHER ///< Use this if the channel is neither an integer or a float
0058     };
0059 
0060 public:
0061     KoChannelInfo() { }
0062     /**
0063      * @param name of the channel
0064      * @param npos position of the channel in the pixel (in bytes)
0065      * @param displayPosition the position of the channel in the user-visible order
0066      * @param channelType type of the channel
0067      * @param channelValueType type of the numerical data used by the channel
0068      * @param size number of bytes (not bits) of the channel (if -1, it is deduced from the channelType)
0069      * @param color a color to represent that channel (for instance in an histogram)
0070      * @param uiMinMax the UI range
0071      */
0072     KoChannelInfo(const QString & name,
0073                   qint32 npos,
0074                   qint32 displayPosition,
0075                   enumChannelType channelType,
0076                   enumChannelValueType channelValueType,
0077                   qint32 size = -1,
0078                   const QColor &color = QColor(0, 0, 0),
0079                   const DoubleRange &uiMinMax = DoubleRange())
0080         : m_name(name)
0081         , m_pos(npos)
0082         , m_displayPosition(displayPosition)
0083         , m_channelType(channelType)
0084         , m_channelValueType(channelValueType)
0085         , m_size(size)
0086         , m_color(color)
0087         , m_uiMinMax(uiMinMax)
0088     {
0089         switch(m_channelValueType)
0090         {
0091         case UINT8:
0092         case INT8:
0093             Q_ASSERT(m_size == -1 || m_size == 1);
0094             m_size = 1;
0095             break;
0096         case UINT16:
0097         case INT16:
0098             Q_ASSERT(m_size == -1 || m_size == 2);
0099             m_size = 2;
0100             break;
0101         case UINT32:
0102             Q_ASSERT(m_size == -1 || m_size == 4);
0103             m_size = 4;
0104             break;
0105         case FLOAT16:
0106             Q_ASSERT(m_size == -1 || m_size == 2);
0107             m_size = 2;
0108             break;
0109         case FLOAT32:
0110             Q_ASSERT(m_size == -1 || m_size == 4);
0111             m_size = 4;
0112             break;
0113         case FLOAT64:
0114             Q_ASSERT(m_size == -1 || m_size == 8);
0115             m_size = 8;
0116             break;
0117         case OTHER:
0118             Q_ASSERT(m_size != -1);
0119         }
0120         if (!uiMinMax.isValid()) {
0121             switch (m_channelValueType) {
0122                 case UINT8:
0123                     m_uiMinMax.minVal = std::numeric_limits<quint8>::min();
0124                     m_uiMinMax.maxVal = std::numeric_limits<quint8>::max();
0125                     break;
0126                 case INT8:
0127                     m_uiMinMax.minVal = std::numeric_limits<qint8>::min();
0128                     m_uiMinMax.maxVal = std::numeric_limits<qint8>::max();
0129                     break;
0130                 case UINT16:
0131                     m_uiMinMax.minVal = std::numeric_limits<quint16>::min();
0132                     m_uiMinMax.maxVal = std::numeric_limits<quint16>::max();
0133                     break;
0134                 case INT16:
0135                     m_uiMinMax.minVal = std::numeric_limits<qint16>::min();
0136                     m_uiMinMax.maxVal = std::numeric_limits<qint16>::max();
0137                     break;
0138                 case UINT32:
0139                     m_uiMinMax.minVal = std::numeric_limits<quint32>::min();
0140                     m_uiMinMax.maxVal = std::numeric_limits<quint32>::max();
0141                     break;
0142                 default:
0143                     // assume real otherwise, which is 0..1 by default
0144                     m_uiMinMax.minVal = 0.0;
0145                     m_uiMinMax.maxVal = 1.0;
0146                     break;
0147             }
0148         }
0149         Q_ASSERT(m_uiMinMax.isValid());
0150     }
0151 public:
0152 
0153     /**
0154      * converts the display position to the pixel-order index in the channels vector.
0155      */
0156     static int displayPositionToChannelIndex(int displayPosition, const QList<KoChannelInfo*> &channels)
0157     {
0158         for (int i = 0; i < channels.size(); ++i) {
0159             if (channels.at(i)->displayPosition() == displayPosition) {
0160                 return i;
0161             }
0162         }
0163         return -1;
0164     }
0165 
0166     static QList<KoChannelInfo*> displayOrderSorted(const QList<KoChannelInfo*> &channels)
0167     {
0168         QList <KoChannelInfo*> sortedChannels;
0169         for (int i = 0; i < channels.size(); ++i) {
0170             Q_FOREACH (KoChannelInfo* channel, channels) {
0171                 if (channel->displayPosition() == i) {
0172                     sortedChannels << channel;
0173                     break;
0174                 }
0175             }
0176         }
0177         Q_ASSERT(channels.size() == sortedChannels.size());
0178         return sortedChannels;
0179     }
0180 
0181     /**
0182      * User-friendly name for this channel for presentation purposes in the gui
0183      */
0184     inline QString name() const {
0185         return m_name;
0186     }
0187 
0188     /**
0189      * @return the position of the first byte of the channel in the pixel
0190      */
0191     inline qint32 pos() const {
0192         return m_pos;
0193     }
0194 
0195     /**
0196      * @return the displayPosition of the channel in the pixel
0197      */
0198     inline qint32 displayPosition() const {
0199         return m_displayPosition;
0200     }
0201 
0202     /**
0203      * @return the number of bytes this channel takes
0204      */
0205     inline qint32 size() const {
0206         return m_size;
0207     }
0208 
0209     /**
0210      * @return the type of the channel
0211      */
0212     inline enumChannelType channelType() const {
0213         return m_channelType;
0214     }
0215     /**
0216      * @return the type of the value of the channel (float, uint8 or uint16)
0217      */
0218     inline enumChannelValueType channelValueType() const {
0219         return m_channelValueType;
0220     }
0221     /**
0222      * This is a color that can be used to represent this channel in histograms and so.
0223      * By default this is black, so keep in mind that many channels might look the same
0224      */
0225     inline QColor color() const {
0226         return m_color;
0227     }
0228 
0229     /**
0230      * A channel is less than another channel if its pos is smaller.
0231      */
0232     inline bool operator<(const KoChannelInfo & info) {
0233         return m_pos < info.m_pos;
0234     }
0235 
0236     /**
0237      * Gets the minimum value that this channel should have.
0238      * This is suitable for UI use.
0239      */
0240     inline double getUIMin(void) const {
0241         return m_uiMinMax.minVal;
0242     }
0243 
0244     /**
0245      * Gets the minimum value that this channel should have.
0246      * This is suitable for UI use.
0247      */
0248     inline double getUIMax(void) const {
0249         return m_uiMinMax.maxVal;
0250     }
0251 
0252     /**
0253      * @brief getUIUnitValue
0254      * Gets the unit value for this channel.
0255      * This is suitable for converting between representations.
0256      */
0257     inline double getUIUnitValue(void) const {
0258         return m_uiMinMax.maxVal - m_uiMinMax.minVal;
0259     }
0260 
0261 private:
0262 
0263     QString m_name;
0264     qint32 m_pos;
0265     qint32 m_displayPosition;
0266     enumChannelType m_channelType;
0267     enumChannelValueType m_channelValueType;
0268     qint32 m_size;
0269     QColor m_color;
0270     DoubleRange m_uiMinMax;
0271 
0272 };
0273 
0274 #endif // KOCHANNELINFO_H_