Coverage Report

Created: 2025-07-12 07:23

/src/qtbase/src/gui/image/qimage_p.h
Line
Count
Source (jump to first uncovered line)
1
/****************************************************************************
2
**
3
** Copyright (C) 2016 The Qt Company Ltd.
4
** Contact: https://www.qt.io/licensing/
5
**
6
** This file is part of the QtGui module of the Qt Toolkit.
7
**
8
** $QT_BEGIN_LICENSE:LGPL$
9
** Commercial License Usage
10
** Licensees holding valid commercial Qt licenses may use this file in
11
** accordance with the commercial license agreement provided with the
12
** Software or, alternatively, in accordance with the terms contained in
13
** a written agreement between you and The Qt Company. For licensing terms
14
** and conditions see https://www.qt.io/terms-conditions. For further
15
** information use the contact form at https://www.qt.io/contact-us.
16
**
17
** GNU Lesser General Public License Usage
18
** Alternatively, this file may be used under the terms of the GNU Lesser
19
** General Public License version 3 as published by the Free Software
20
** Foundation and appearing in the file LICENSE.LGPL3 included in the
21
** packaging of this file. Please review the following information to
22
** ensure the GNU Lesser General Public License version 3 requirements
23
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24
**
25
** GNU General Public License Usage
26
** Alternatively, this file may be used under the terms of the GNU
27
** General Public License version 2.0 or (at your option) the GNU General
28
** Public license version 3 or any later version approved by the KDE Free
29
** Qt Foundation. The licenses are as published by the Free Software
30
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31
** included in the packaging of this file. Please review the following
32
** information to ensure the GNU General Public License requirements will
33
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34
** https://www.gnu.org/licenses/gpl-3.0.html.
35
**
36
** $QT_END_LICENSE$
37
**
38
****************************************************************************/
39
40
#ifndef QIMAGE_P_H
41
#define QIMAGE_P_H
42
43
//
44
//  W A R N I N G
45
//  -------------
46
//
47
// This file is not part of the Qt API.  It exists purely as an
48
// implementation detail.  This header file may change from version to
49
// version without notice, or even be removed.
50
//
51
// We mean it.
52
//
53
54
#include <QtGui/qcolorspace.h>
55
#include <QtGui/private/qtguiglobal_p.h>
56
#include <QtGui/qimage.h>
57
#include <QtCore/private/qnumeric_p.h>
58
59
#include <QMap>
60
#include <QVector>
61
62
QT_BEGIN_NAMESPACE
63
64
class QImageWriter;
65
66
struct Q_GUI_EXPORT QImageData {        // internal image data
67
    QImageData();
68
    ~QImageData();
69
    static QImageData *create(const QSize &size, QImage::Format format);
70
    static QImageData *create(uchar *data, int w, int h,  int bpl, QImage::Format format, bool readOnly, QImageCleanupFunction cleanupFunction = nullptr, void *cleanupInfo = nullptr);
71
72
0
    static QImageData *get(QImage &img) noexcept { return img.d; }
73
0
    static const QImageData *get(const QImage &img) noexcept { return img.d; }
74
75
    QAtomicInt ref;
76
77
    int width;
78
    int height;
79
    int depth;
80
    qsizetype nbytes;               // number of bytes data
81
    qreal devicePixelRatio;
82
    QVector<QRgb> colortable;
83
    uchar *data;
84
    QImage::Format format;
85
    qsizetype bytes_per_line;
86
    int ser_no;               // serial number
87
    int detach_no;
88
89
    qreal  dpmx;                // dots per meter X (or 0)
90
    qreal  dpmy;                // dots per meter Y (or 0)
91
    QPoint  offset;           // offset in pixels
92
93
    uint own_data : 1;
94
    uint ro_data : 1;
95
    uint has_alpha_clut : 1;
96
    uint is_cached : 1;
97
    uint is_locked : 1;
98
99
    QImageCleanupFunction cleanupFunction;
100
    void* cleanupInfo;
101
102
    bool checkForAlphaPixels() const;
103
104
    // Convert the image in-place, minimizing memory reallocation
105
    // Return false if the conversion cannot be done in-place.
106
    bool convertInPlace(QImage::Format newFormat, Qt::ImageConversionFlags);
107
108
    QMap<QString, QString> text;
109
110
    bool doImageIO(const QImage *image, QImageWriter* io, int quality) const;
111
112
    QPaintEngine *paintEngine;
113
114
    QColorSpace colorSpace;
115
116
    struct ImageSizeParameters {
117
        qsizetype bytesPerLine;
118
        qsizetype totalSize;
119
63.0k
        bool isValid() const { return bytesPerLine > 0 && totalSize > 0; }
120
    };
121
    static ImageSizeParameters calculateImageParameters(qsizetype width, qsizetype height, qsizetype depth);
122
};
123
124
inline QImageData::ImageSizeParameters
125
QImageData::calculateImageParameters(qsizetype width, qsizetype height, qsizetype depth)
126
63.0k
{
127
63.0k
    ImageSizeParameters invalid = { -1, -1 };
128
63.0k
    if (height <= 0)
129
0
        return invalid;
130
131
    // calculate the size, taking care of overflows
132
63.0k
    qsizetype bytes_per_line;
133
63.0k
    if (mul_overflow(width, depth, &bytes_per_line))
134
0
        return invalid;
135
63.0k
    if (add_overflow(bytes_per_line, qsizetype(31), &bytes_per_line))
136
0
        return invalid;
137
    // bytes per scanline (must be multiple of 4)
138
63.0k
    bytes_per_line = (bytes_per_line >> 5) << 2;    // can't overflow
139
140
63.0k
    qsizetype total_size;
141
63.0k
    if (mul_overflow(height, bytes_per_line, &total_size))
142
0
        return invalid;
143
63.0k
    qsizetype dummy;
144
63.0k
    if (mul_overflow(height, qsizetype(sizeof(uchar *)), &dummy))
145
0
        return invalid;                                 // why is this here?
146
63.0k
#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
147
    // Disallow images where width * depth calculations might overflow
148
63.0k
    if (width > (INT_MAX - 31) / depth)
149
0
        return invalid;
150
63.0k
#endif
151
152
63.0k
    return { bytes_per_line, total_size };
153
63.0k
}
154
155
typedef void (*Image_Converter)(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags);
156
typedef bool (*InPlace_Image_Converter)(QImageData *data, Qt::ImageConversionFlags);
157
158
extern Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormats];
159
extern InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QImage::NImageFormats];
160
161
void convert_generic(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags);
162
void convert_generic_to_rgb64(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags);
163
bool convert_generic_inplace(QImageData *data, QImage::Format dst_format, Qt::ImageConversionFlags);
164
165
void dither_to_Mono(QImageData *dst, const QImageData *src, Qt::ImageConversionFlags flags, bool fromalpha);
166
167
const uchar *qt_get_bitflip_array();
168
Q_GUI_EXPORT void qGamma_correct_back_to_linear_cs(QImage *image);
169
170
#if defined(_M_ARM) && defined(_MSC_VER) // QTBUG-42038
171
#pragma optimize("", off)
172
#endif
173
inline int qt_depthForFormat(QImage::Format format)
174
63.0k
{
175
63.0k
    int depth = 0;
176
63.0k
    switch(format) {
177
0
    case QImage::Format_Invalid:
178
0
    case QImage::NImageFormats:
179
0
        Q_UNREACHABLE();
180
0
    case QImage::Format_Mono:
181
0
    case QImage::Format_MonoLSB:
182
0
        depth = 1;
183
0
        break;
184
0
    case QImage::Format_Indexed8:
185
0
    case QImage::Format_Alpha8:
186
0
    case QImage::Format_Grayscale8:
187
0
        depth = 8;
188
0
        break;
189
63.0k
    case QImage::Format_RGB32:
190
63.0k
    case QImage::Format_ARGB32:
191
63.0k
    case QImage::Format_ARGB32_Premultiplied:
192
63.0k
    case QImage::Format_RGBX8888:
193
63.0k
    case QImage::Format_RGBA8888:
194
63.0k
    case QImage::Format_RGBA8888_Premultiplied:
195
63.0k
    case QImage::Format_BGR30:
196
63.0k
    case QImage::Format_A2BGR30_Premultiplied:
197
63.0k
    case QImage::Format_RGB30:
198
63.0k
    case QImage::Format_A2RGB30_Premultiplied:
199
63.0k
        depth = 32;
200
63.0k
        break;
201
0
    case QImage::Format_RGB555:
202
0
    case QImage::Format_RGB16:
203
0
    case QImage::Format_RGB444:
204
0
    case QImage::Format_ARGB4444_Premultiplied:
205
0
    case QImage::Format_Grayscale16:
206
0
        depth = 16;
207
0
        break;
208
0
    case QImage::Format_RGB666:
209
0
    case QImage::Format_ARGB6666_Premultiplied:
210
0
    case QImage::Format_ARGB8565_Premultiplied:
211
0
    case QImage::Format_ARGB8555_Premultiplied:
212
0
    case QImage::Format_RGB888:
213
0
    case QImage::Format_BGR888:
214
0
        depth = 24;
215
0
        break;
216
0
    case QImage::Format_RGBX64:
217
0
    case QImage::Format_RGBA64:
218
0
    case QImage::Format_RGBA64_Premultiplied:
219
0
        depth = 64;
220
0
        break;
221
63.0k
    }
222
63.0k
    return depth;
223
63.0k
}
224
225
#if defined(_M_ARM) && defined(_MSC_VER)
226
#pragma optimize("", on)
227
#endif
228
229
inline QImage::Format qt_opaqueVersion(QImage::Format format)
230
0
{
231
0
    switch (format) {
232
0
    case QImage::Format_ARGB8565_Premultiplied:
233
0
        return  QImage::Format_RGB16;
234
0
    case QImage::Format_ARGB8555_Premultiplied:
235
0
        return QImage::Format_RGB555;
236
0
    case QImage::Format_ARGB6666_Premultiplied:
237
0
        return  QImage::Format_RGB666;
238
0
    case QImage::Format_ARGB4444_Premultiplied:
239
0
        return QImage::Format_RGB444;
240
0
    case QImage::Format_RGBA8888:
241
0
    case QImage::Format_RGBA8888_Premultiplied:
242
0
        return QImage::Format_RGBX8888;
243
0
    case QImage::Format_A2BGR30_Premultiplied:
244
0
        return QImage::Format_BGR30;
245
0
    case QImage::Format_A2RGB30_Premultiplied:
246
0
        return QImage::Format_RGB30;
247
0
    case QImage::Format_RGBA64:
248
0
    case QImage::Format_RGBA64_Premultiplied:
249
0
        return QImage::Format_RGBX64;
250
0
    case QImage::Format_ARGB32_Premultiplied:
251
0
    case QImage::Format_ARGB32:
252
0
        return QImage::Format_RGB32;
253
0
    case QImage::Format_RGB16:
254
0
    case QImage::Format_RGB32:
255
0
    case QImage::Format_RGB444:
256
0
    case QImage::Format_RGB555:
257
0
    case QImage::Format_RGB666:
258
0
    case QImage::Format_RGB888:
259
0
    case QImage::Format_BGR888:
260
0
    case QImage::Format_RGBX8888:
261
0
    case QImage::Format_BGR30:
262
0
    case QImage::Format_RGB30:
263
0
    case QImage::Format_RGBX64:
264
0
    case QImage::Format_Grayscale8:
265
0
    case QImage::Format_Grayscale16:
266
0
        return format;
267
0
    case QImage::Format_Mono:
268
0
    case QImage::Format_MonoLSB:
269
0
    case QImage::Format_Indexed8:
270
0
    case QImage::Format_Alpha8:
271
0
    case QImage::Format_Invalid:
272
0
    case QImage::NImageFormats:
273
0
        break;
274
0
    }
275
0
    return QImage::Format_RGB32;
276
0
}
277
278
inline QImage::Format qt_alphaVersion(QImage::Format format)
279
0
{
280
0
    switch (format) {
281
0
    case QImage::Format_RGB32:
282
0
    case QImage::Format_ARGB32:
283
0
        return QImage::Format_ARGB32_Premultiplied;
284
0
    case QImage::Format_RGB16:
285
0
        return QImage::Format_ARGB8565_Premultiplied;
286
0
    case QImage::Format_RGB555:
287
0
        return QImage::Format_ARGB8555_Premultiplied;
288
0
    case QImage::Format_RGB666:
289
0
        return QImage::Format_ARGB6666_Premultiplied;
290
0
    case QImage::Format_RGB444:
291
0
        return QImage::Format_ARGB4444_Premultiplied;
292
0
    case QImage::Format_RGBX8888:
293
0
    case QImage::Format_RGBA8888:
294
0
        return QImage::Format_RGBA8888_Premultiplied;
295
0
    case QImage::Format_BGR30:
296
0
        return QImage::Format_A2BGR30_Premultiplied;
297
0
    case QImage::Format_RGB30:
298
0
        return QImage::Format_A2RGB30_Premultiplied;
299
0
    case QImage::Format_RGBX64:
300
0
    case QImage::Format_RGBA64:
301
0
    case QImage::Format_Grayscale16:
302
0
        return QImage::Format_RGBA64_Premultiplied;
303
0
    case QImage::Format_ARGB32_Premultiplied:
304
0
    case QImage::Format_ARGB8565_Premultiplied:
305
0
    case QImage::Format_ARGB8555_Premultiplied:
306
0
    case QImage::Format_ARGB6666_Premultiplied:
307
0
    case QImage::Format_ARGB4444_Premultiplied:
308
0
    case QImage::Format_RGBA8888_Premultiplied:
309
0
    case QImage::Format_A2BGR30_Premultiplied:
310
0
    case QImage::Format_A2RGB30_Premultiplied:
311
0
    case QImage::Format_RGBA64_Premultiplied:
312
0
        return format;
313
0
    case QImage::Format_Mono:
314
0
    case QImage::Format_MonoLSB:
315
0
    case QImage::Format_Indexed8:
316
0
    case QImage::Format_RGB888:
317
0
    case QImage::Format_BGR888:
318
0
    case QImage::Format_Alpha8:
319
0
    case QImage::Format_Grayscale8:
320
0
    case QImage::Format_Invalid:
321
0
    case QImage::NImageFormats:
322
0
        break;
323
0
    }
324
0
    return QImage::Format_ARGB32_Premultiplied;
325
0
}
326
327
inline bool qt_highColorPrecision(QImage::Format format, bool opaque = false)
328
0
{
329
    // Formats with higher color precision than ARGB32_Premultiplied.
330
0
    switch (format) {
331
0
    case QImage::Format_ARGB32:
332
0
    case QImage::Format_RGBA8888:
333
0
        return !opaque;
334
0
    case QImage::Format_BGR30:
335
0
    case QImage::Format_RGB30:
336
0
    case QImage::Format_A2BGR30_Premultiplied:
337
0
    case QImage::Format_A2RGB30_Premultiplied:
338
0
    case QImage::Format_RGBX64:
339
0
    case QImage::Format_RGBA64:
340
0
    case QImage::Format_RGBA64_Premultiplied:
341
0
    case QImage::Format_Grayscale16:
342
0
        return true;
343
0
    default:
344
0
        break;
345
0
    }
346
0
    return false;
347
0
}
348
349
350
inline QImage::Format qt_maybeAlphaVersionWithSameDepth(QImage::Format format)
351
0
{
352
0
    const QImage::Format toFormat = qt_alphaVersion(format);
353
0
    return qt_depthForFormat(format) == qt_depthForFormat(toFormat) ? toFormat : format;
354
0
}
355
356
inline QImage::Format qt_opaqueVersionForPainting(QImage::Format format)
357
0
{
358
0
    QImage::Format toFormat = qt_opaqueVersion(format);
359
0
    // If we are switching depth anyway upgrade to RGB32
360
0
    if (qt_depthForFormat(format) != qt_depthForFormat(toFormat) && qt_depthForFormat(toFormat) <= 32)
361
0
        toFormat = QImage::Format_RGB32;
362
0
    return toFormat;
363
0
}
364
365
inline QImage::Format qt_alphaVersionForPainting(QImage::Format format)
366
0
{
367
0
    QImage::Format toFormat = qt_alphaVersion(format);
368
0
#if defined(__ARM_NEON__) || defined(__SSE2__)
369
    // If we are switching depth anyway and we have optimized ARGB32PM routines, upgrade to that.
370
0
    if (qt_depthForFormat(format) != qt_depthForFormat(toFormat) && qt_depthForFormat(toFormat) <= 32)
371
0
        toFormat = QImage::Format_ARGB32_Premultiplied;
372
0
#endif
373
0
    return toFormat;
374
0
}
375
376
Q_GUI_EXPORT QMap<QString, QString> qt_getImageText(const QImage &image, const QString &description);
377
Q_GUI_EXPORT QMap<QString, QString> qt_getImageTextFromDescription(const QString &description);
378
379
QT_END_NAMESPACE
380
381
#endif // QIMAGE_P_H