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 
getQImageData72     static QImageData *get(QImage &img) noexcept { return img.d; }
getQImageData73     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;
isValidQImageData::ImageSizeParameters119         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
calculateImageParameters(qsizetype width,qsizetype height,qsizetype depth)125 QImageData::calculateImageParameters(qsizetype width, qsizetype height, qsizetype depth)
126 {
127     ImageSizeParameters invalid = { -1, -1 };
128     if (height <= 0)
129         return invalid;
130 
131     // calculate the size, taking care of overflows
132     qsizetype bytes_per_line;
133     if (mul_overflow(width, depth, &bytes_per_line))
134         return invalid;
135     if (add_overflow(bytes_per_line, qsizetype(31), &bytes_per_line))
136         return invalid;
137     // bytes per scanline (must be multiple of 4)
138     bytes_per_line = (bytes_per_line >> 5) << 2;    // can't overflow
139 
140     qsizetype total_size;
141     if (mul_overflow(height, bytes_per_line, &total_size))
142         return invalid;
143     qsizetype dummy;
144     if (mul_overflow(height, qsizetype(sizeof(uchar *)), &dummy))
145         return invalid;                                 // why is this here?
146 #if QT_VERSION < QT_VERSION_CHECK(6,0,0)
147     // Disallow images where width * depth calculations might overflow
148     if (width > (INT_MAX - 31) / depth)
149         return invalid;
150 #endif
151 
152     return { bytes_per_line, total_size };
153 }
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
qt_depthForFormat(QImage::Format format)173 inline 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 
qt_opaqueVersion(QImage::Format format)229 inline 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     default:
253         return QImage::Format_RGB32;
254     }
255 }
256 
qt_alphaVersion(QImage::Format format)257 inline QImage::Format qt_alphaVersion(QImage::Format format)
258 {
259     switch (format) {
260     case QImage::Format_RGB16:
261         return QImage::Format_ARGB8565_Premultiplied;
262     case QImage::Format_RGB555:
263         return QImage::Format_ARGB8555_Premultiplied;
264     case QImage::Format_RGB666:
265         return QImage::Format_ARGB6666_Premultiplied;
266     case QImage::Format_RGB444:
267         return QImage::Format_ARGB4444_Premultiplied;
268     case QImage::Format_RGBX8888:
269         return QImage::Format_RGBA8888_Premultiplied;
270     case QImage::Format_BGR30:
271         return QImage::Format_A2BGR30_Premultiplied;
272     case QImage::Format_RGB30:
273         return QImage::Format_A2RGB30_Premultiplied;
274     case QImage::Format_RGBX64:
275         return QImage::Format_RGBA64_Premultiplied;
276     default:
277         break;
278     }
279     return QImage::Format_ARGB32_Premultiplied;
280 }
281 
282 inline bool qt_highColorPrecision(QImage::Format format, bool opaque = false)
283 {
284     // Formats with higher color precision than ARGB32_Premultiplied.
285     switch (format) {
286     case QImage::Format_ARGB32:
287     case QImage::Format_RGBA8888:
288         return !opaque;
289     case QImage::Format_BGR30:
290     case QImage::Format_RGB30:
291     case QImage::Format_A2BGR30_Premultiplied:
292     case QImage::Format_A2RGB30_Premultiplied:
293     case QImage::Format_RGBX64:
294     case QImage::Format_RGBA64:
295     case QImage::Format_RGBA64_Premultiplied:
296     case QImage::Format_Grayscale16:
297         return true;
298     default:
299         break;
300     }
301     return false;
302 }
303 
304 
qt_maybeAlphaVersionWithSameDepth(QImage::Format format)305 inline QImage::Format qt_maybeAlphaVersionWithSameDepth(QImage::Format format)
306 {
307     const QImage::Format toFormat = qt_alphaVersion(format);
308     return qt_depthForFormat(format) == qt_depthForFormat(toFormat) ? toFormat : format;
309 }
310 
qt_opaqueVersionForPainting(QImage::Format format)311 inline QImage::Format qt_opaqueVersionForPainting(QImage::Format format)
312 {
313     return qt_opaqueVersion(format);
314 }
315 
qt_alphaVersionForPainting(QImage::Format format)316 inline QImage::Format qt_alphaVersionForPainting(QImage::Format format)
317 {
318     QImage::Format toFormat = qt_alphaVersion(format);
319 #if defined(__ARM_NEON__) || defined(__SSE2__)
320     // If we are switching depth anyway and we have optimized ARGB32PM routines, upgrade to that.
321     if (qt_depthForFormat(format) != qt_depthForFormat(toFormat))
322         toFormat = QImage::Format_ARGB32_Premultiplied;
323 #endif
324     return toFormat;
325 }
326 
327 Q_GUI_EXPORT QMap<QString, QString> qt_getImageText(const QImage &image, const QString &description);
328 Q_GUI_EXPORT QMap<QString, QString> qt_getImageTextFromDescription(const QString &description);
329 
330 QT_END_NAMESPACE
331 
332 #endif // QIMAGE_P_H
333