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/private/qtguiglobal_p.h>
55#include <QtGui/qcolorspace.h>
56#include <QtGui/qimage.h>
57#include <QtCore/private/qnumeric_p.h>
58#include <QtCore/qlist.h>
59#include <QtCore/qmap.h>
60
61QT_BEGIN_NAMESPACE
62
63class QImageWriter;
64
65struct Q_GUI_EXPORT QImageData { // internal image data
66 QImageData();
67 ~QImageData();
68 static QImageData *create(const QSize &size, QImage::Format format);
69 static QImageData *create(uchar *data, int w, int h, qsizetype bpl, QImage::Format format, bool readOnly, QImageCleanupFunction cleanupFunction = nullptr, void *cleanupInfo = nullptr);
70
71 static QImageData *get(QImage &img) noexcept { return img.d; }
72 static const QImageData *get(const QImage &img) noexcept { return img.d; }
73
74 QAtomicInt ref;
75
76 int width;
77 int height;
78 int depth;
79 qsizetype nbytes; // number of bytes data
80 qreal devicePixelRatio;
81 QList<QRgb> colortable;
82 uchar *data;
83 QImage::Format format;
84 qsizetype bytes_per_line;
85 int ser_no; // serial number
86 int detach_no;
87
88 qreal dpmx; // dots per meter X (or 0)
89 qreal dpmy; // dots per meter Y (or 0)
90 QPoint offset; // offset in pixels
91
92 uint own_data : 1;
93 uint ro_data : 1;
94 uint has_alpha_clut : 1;
95 uint is_cached : 1;
96 uint is_locked : 1;
97
98 QImageCleanupFunction cleanupFunction;
99 void* cleanupInfo;
100
101 bool checkForAlphaPixels() const;
102
103 // Convert the image in-place, minimizing memory reallocation
104 // Return false if the conversion cannot be done in-place.
105 bool convertInPlace(QImage::Format newFormat, Qt::ImageConversionFlags);
106
107 QMap<QString, QString> text;
108
109 bool doImageIO(const QImage *image, QImageWriter* io, int quality) const;
110
111 QPaintEngine *paintEngine;
112
113 QColorSpace colorSpace;
114
115 struct ImageSizeParameters {
116 qsizetype bytesPerLine;
117 qsizetype totalSize;
118 bool isValid() const { return bytesPerLine > 0 && totalSize > 0; }
119 };
120 static ImageSizeParameters calculateImageParameters(qsizetype width, qsizetype height, qsizetype depth);
121};
122
123inline QImageData::ImageSizeParameters
124QImageData::calculateImageParameters(qsizetype width, qsizetype height, qsizetype depth)
125{
126 ImageSizeParameters invalid = { -1, -1 };
127 if (height <= 0)
128 return invalid;
129
130 // calculate the size, taking care of overflows
131 qsizetype bytes_per_line;
132 if (mul_overflow(width, depth, &bytes_per_line))
133 return invalid;
134 if (add_overflow(bytes_per_line, qsizetype(31), &bytes_per_line))
135 return invalid;
136 // bytes per scanline (must be multiple of 4)
137 bytes_per_line = (bytes_per_line >> 5) << 2; // can't overflow
138
139 qsizetype total_size;
140 if (mul_overflow(height, bytes_per_line, &total_size))
141 return invalid;
142 qsizetype dummy;
143 if (mul_overflow(height, qsizetype(sizeof(uchar *)), &dummy))
144 return invalid; // why is this here?
145#if 1 || QT_VERSION < QT_VERSION_CHECK(6,0,0) // ### can only fix this if QImage dimensions are not int anymore
146 // Disallow images where width * depth calculations might overflow
147 if (width > (INT_MAX - 31) / depth)
148 return invalid;
149#endif
150
151 return { bytes_per_line, total_size };
152}
153
154typedef void (*Image_Converter)(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags);
155typedef bool (*InPlace_Image_Converter)(QImageData *data, Qt::ImageConversionFlags);
156
157extern Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormats];
158extern InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QImage::NImageFormats];
159
160void convert_generic(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags);
161void convert_generic_over_rgb64(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags);
162bool convert_generic_inplace(QImageData *data, QImage::Format dst_format, Qt::ImageConversionFlags);
163bool convert_generic_inplace_over_rgb64(QImageData *data, QImage::Format dst_format, Qt::ImageConversionFlags);
164
165void dither_to_Mono(QImageData *dst, const QImageData *src, Qt::ImageConversionFlags flags, bool fromalpha);
166
167const uchar *qt_get_bitflip_array();
168Q_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
173inline int qt_depthForFormat(QImage::Format format)
174{
175 int depth = 0;
176 switch(format) {
177 case QImage::Format_Invalid:
178 case QImage::NImageFormats:
179 Q_UNREACHABLE();
180 case QImage::Format_Mono:
181 case QImage::Format_MonoLSB:
182 depth = 1;
183 break;
184 case QImage::Format_Indexed8:
185 case QImage::Format_Alpha8:
186 case QImage::Format_Grayscale8:
187 depth = 8;
188 break;
189 case QImage::Format_RGB32:
190 case QImage::Format_ARGB32:
191 case QImage::Format_ARGB32_Premultiplied:
192 case QImage::Format_RGBX8888:
193 case QImage::Format_RGBA8888:
194 case QImage::Format_RGBA8888_Premultiplied:
195 case QImage::Format_BGR30:
196 case QImage::Format_A2BGR30_Premultiplied:
197 case QImage::Format_RGB30:
198 case QImage::Format_A2RGB30_Premultiplied:
199 depth = 32;
200 break;
201 case QImage::Format_RGB555:
202 case QImage::Format_RGB16:
203 case QImage::Format_RGB444:
204 case QImage::Format_ARGB4444_Premultiplied:
205 case QImage::Format_Grayscale16:
206 depth = 16;
207 break;
208 case QImage::Format_RGB666:
209 case QImage::Format_ARGB6666_Premultiplied:
210 case QImage::Format_ARGB8565_Premultiplied:
211 case QImage::Format_ARGB8555_Premultiplied:
212 case QImage::Format_RGB888:
213 case QImage::Format_BGR888:
214 depth = 24;
215 break;
216 case QImage::Format_RGBX64:
217 case QImage::Format_RGBA64:
218 case QImage::Format_RGBA64_Premultiplied:
219 depth = 64;
220 break;
221 }
222 return depth;
223}
224
225#if defined(_M_ARM) && defined(_MSC_VER)
226#pragma optimize("", on)
227#endif
228
229inline QImage::Format qt_opaqueVersion(QImage::Format format)
230{
231 switch (format) {
232 case QImage::Format_ARGB8565_Premultiplied:
233 return QImage::Format_RGB16;
234 case QImage::Format_ARGB8555_Premultiplied:
235 return QImage::Format_RGB555;
236 case QImage::Format_ARGB6666_Premultiplied:
237 return QImage::Format_RGB666;
238 case QImage::Format_ARGB4444_Premultiplied:
239 return QImage::Format_RGB444;
240 case QImage::Format_RGBA8888:
241 case QImage::Format_RGBA8888_Premultiplied:
242 return QImage::Format_RGBX8888;
243 case QImage::Format_A2BGR30_Premultiplied:
244 return QImage::Format_BGR30;
245 case QImage::Format_A2RGB30_Premultiplied:
246 return QImage::Format_RGB30;
247 case QImage::Format_RGBA64:
248 case QImage::Format_RGBA64_Premultiplied:
249 return QImage::Format_RGBX64;
250 case QImage::Format_ARGB32_Premultiplied:
251 case QImage::Format_ARGB32:
252 return QImage::Format_RGB32;
253 case QImage::Format_RGB16:
254 case QImage::Format_RGB32:
255 case QImage::Format_RGB444:
256 case QImage::Format_RGB555:
257 case QImage::Format_RGB666:
258 case QImage::Format_RGB888:
259 case QImage::Format_BGR888:
260 case QImage::Format_RGBX8888:
261 case QImage::Format_BGR30:
262 case QImage::Format_RGB30:
263 case QImage::Format_RGBX64:
264 case QImage::Format_Grayscale8:
265 case QImage::Format_Grayscale16:
266 return format;
267 case QImage::Format_Mono:
268 case QImage::Format_MonoLSB:
269 case QImage::Format_Indexed8:
270 case QImage::Format_Alpha8:
271 case QImage::Format_Invalid:
272 case QImage::NImageFormats:
273 break;
274 }
275 return QImage::Format_RGB32;
276}
277
278inline QImage::Format qt_alphaVersion(QImage::Format format)
279{
280 switch (format) {
281 case QImage::Format_RGB32:
282 case QImage::Format_ARGB32:
283 return QImage::Format_ARGB32_Premultiplied;
284 case QImage::Format_RGB16:
285 return QImage::Format_ARGB8565_Premultiplied;
286 case QImage::Format_RGB555:
287 return QImage::Format_ARGB8555_Premultiplied;
288 case QImage::Format_RGB666:
289 return QImage::Format_ARGB6666_Premultiplied;
290 case QImage::Format_RGB444:
291 return QImage::Format_ARGB4444_Premultiplied;
292 case QImage::Format_RGBX8888:
293 case QImage::Format_RGBA8888:
294 return QImage::Format_RGBA8888_Premultiplied;
295 case QImage::Format_BGR30:
296 return QImage::Format_A2BGR30_Premultiplied;
297 case QImage::Format_RGB30:
298 return QImage::Format_A2RGB30_Premultiplied;
299 case QImage::Format_RGBX64:
300 case QImage::Format_RGBA64:
301 case QImage::Format_Grayscale16:
302 return QImage::Format_RGBA64_Premultiplied;
303 case QImage::Format_ARGB32_Premultiplied:
304 case QImage::Format_ARGB8565_Premultiplied:
305 case QImage::Format_ARGB8555_Premultiplied:
306 case QImage::Format_ARGB6666_Premultiplied:
307 case QImage::Format_ARGB4444_Premultiplied:
308 case QImage::Format_RGBA8888_Premultiplied:
309 case QImage::Format_A2BGR30_Premultiplied:
310 case QImage::Format_A2RGB30_Premultiplied:
311 case QImage::Format_RGBA64_Premultiplied:
312 return format;
313 case QImage::Format_Mono:
314 case QImage::Format_MonoLSB:
315 case QImage::Format_Indexed8:
316 case QImage::Format_RGB888:
317 case QImage::Format_BGR888:
318 case QImage::Format_Alpha8:
319 case QImage::Format_Grayscale8:
320 case QImage::Format_Invalid:
321 case QImage::NImageFormats:
322 break;
323 }
324 return QImage::Format_ARGB32_Premultiplied;
325}
326
327inline bool qt_highColorPrecision(QImage::Format format, bool opaque = false)
328{
329 // Formats with higher color precision than ARGB32_Premultiplied.
330 switch (format) {
331 case QImage::Format_ARGB32:
332 case QImage::Format_RGBA8888:
333 return !opaque;
334 case QImage::Format_BGR30:
335 case QImage::Format_RGB30:
336 case QImage::Format_A2BGR30_Premultiplied:
337 case QImage::Format_A2RGB30_Premultiplied:
338 case QImage::Format_RGBX64:
339 case QImage::Format_RGBA64:
340 case QImage::Format_RGBA64_Premultiplied:
341 case QImage::Format_Grayscale16:
342 return true;
343 default:
344 break;
345 }
346 return false;
347}
348
349
350inline QImage::Format qt_maybeAlphaVersionWithSameDepth(QImage::Format format)
351{
352 const QImage::Format toFormat = qt_alphaVersion(format);
353 return qt_depthForFormat(format) == qt_depthForFormat(toFormat) ? toFormat : format;
354}
355
356inline QImage::Format qt_opaqueVersionForPainting(QImage::Format format)
357{
358 QImage::Format toFormat = qt_opaqueVersion(format);
359 // If we are switching depth anyway upgrade to RGB32
360 if (qt_depthForFormat(format) != qt_depthForFormat(toFormat) && qt_depthForFormat(toFormat) <= 32)
361 toFormat = QImage::Format_RGB32;
362 return toFormat;
363}
364
365inline QImage::Format qt_alphaVersionForPainting(QImage::Format format)
366{
367 QImage::Format toFormat = qt_alphaVersion(format);
368#if defined(__ARM_NEON__) || defined(__SSE2__)
369 // If we are switching depth anyway and we have optimized ARGB32PM routines, upgrade to that.
370 if (qt_depthForFormat(format) != qt_depthForFormat(toFormat) && qt_depthForFormat(toFormat) <= 32)
371 toFormat = QImage::Format_ARGB32_Premultiplied;
372#endif
373 return toFormat;
374}
375
376Q_GUI_EXPORT QMap<QString, QString> qt_getImageText(const QImage &image, const QString &description);
377Q_GUI_EXPORT QMap<QString, QString> qt_getImageTextFromDescription(const QString &description);
378
379QT_END_NAMESPACE
380
381#endif // QIMAGE_P_H
382