Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qddshandler.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// Copyright (C) 2016 Ivan Komissarov.
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4
5#include "qddshandler.h"
6
7#include <QtCore/qdebug.h>
8#include <QtGui/qimage.h>
9
10#include <cmath>
11
12#include "ddsheader.h"
13
14#include <cmath>
15
16#ifndef QT_NO_DATASTREAM
17
19
27
29 One = 1,
30 Two = 2,
31 Three = 3,
32 Four = 4,
33 Five = 5,
34 RXGB = 6
35};
36
37// All magic numbers are little-endian as long as dds format has little
38// endian byte order
39static const quint32 ddsMagic = 0x20534444; // "DDS "
40static const quint32 dx10Magic = 0x30315844; // "DX10"
41
42static const qint64 headerSize = 128;
43static const quint32 ddsSize = 124; // headerSize without magic
44static const quint32 pixelFormatSize = 32;
45
47{
48 int x, y;
49};
50
51static const FaceOffset faceOffsets[6] = { {2, 1}, {0, 1}, {1, 0}, {1, 2}, {1, 1}, {3, 1} };
52
61
72
73static const FormatInfo formatInfos[] = {
74 { FormatA8R8G8B8, DDSPixelFormat::FlagRGBA, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000 },
75 { FormatX8R8G8B8, DDSPixelFormat::FlagRGB, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000 },
76 { FormatA2B10G10R10, DDSPixelFormat::FlagRGBA, 32, 0x000003ff, 0x000ffc00, 0x3ff00000, 0xc0000000 },
77 { FormatA8B8G8R8, DDSPixelFormat::FlagRGBA, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000 },
78 { FormatX8B8G8R8, DDSPixelFormat::FlagRGB, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0x00000000 },
79 { FormatG16R16, DDSPixelFormat::FlagRGBA, 32, 0x0000ffff, 0xffff0000, 0x00000000, 0x00000000 },
80 { FormatG16R16, DDSPixelFormat::FlagRGB, 32, 0x0000ffff, 0xffff0000, 0x00000000, 0x00000000 },
81 { FormatA2R10G10B10, DDSPixelFormat::FlagRGBA, 32, 0x3ff00000, 0x000ffc00, 0x000003ff, 0xc0000000 },
82
83 { FormatR8G8B8, DDSPixelFormat::FlagRGB, 24, 0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000 },
84
85 { FormatR5G6B5, DDSPixelFormat::FlagRGB, 16, 0x0000f800, 0x000007e0, 0x0000001f, 0x00000000 },
86 { FormatX1R5G5B5, DDSPixelFormat::FlagRGB, 16, 0x00007c00, 0x000003e0, 0x0000001f, 0x00000000 },
87 { FormatA1R5G5B5, DDSPixelFormat::FlagRGBA, 16, 0x00007c00, 0x000003e0, 0x0000001f, 0x00008000 },
88 { FormatA4R4G4B4, DDSPixelFormat::FlagRGBA, 16, 0x00000f00, 0x000000f0, 0x0000000f, 0x0000f000 },
89 { FormatA8R3G3B2, DDSPixelFormat::FlagRGBA, 16, 0x000000e0, 0x0000001c, 0x00000003, 0x0000ff00 },
90 { FormatX4R4G4B4, DDSPixelFormat::FlagRGB, 16, 0x00000f00, 0x000000f0, 0x0000000f, 0x00000000 },
91 { FormatA8L8, DDSPixelFormat::FlagLA, 16, 0x000000ff, 0x00000000, 0x00000000, 0x0000ff00 },
92 { FormatL16, DDSPixelFormat::FlagLuminance, 16, 0x0000ffff, 0x00000000, 0x00000000, 0x00000000 },
93
94 { FormatR3G3B2, DDSPixelFormat::FlagRGB, 8, 0x000000e0, 0x0000001c, 0x00000003, 0x00000000 },
95 { FormatA8, DDSPixelFormat::FlagAlpha, 8, 0x00000000, 0x00000000, 0x00000000, 0x000000ff },
96 { FormatL8, DDSPixelFormat::FlagLuminance, 8, 0x000000ff, 0x00000000, 0x00000000, 0x00000000 },
97 { FormatA4L4, DDSPixelFormat::FlagLA, 8, 0x0000000f, 0x00000000, 0x00000000, 0x000000f0 },
98
99 { FormatV8U8, DDSPixelFormat::FlagNormal, 16, 0x000000ff, 0x0000ff00, 0x00000000, 0x00000000 },
100 { FormatL6V5U5, 0, 16, 0x0000001f, 0x000003e0, 0x0000fc00, 0x00000000 },
101 { FormatX8L8V8U8, 0, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0x00000000 },
102 { FormatQ8W8V8U8, DDSPixelFormat::FlagNormal, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000 },
103 { FormatV16U16, DDSPixelFormat::FlagNormal, 32, 0x0000ffff, 0xffff0000, 0x00000000, 0x00000000 },
104 { FormatA2W10V10U10, DDSPixelFormat::FlagNormal, 32, 0x3ff00000, 0x000ffc00, 0x000003ff, 0xc0000000 }
105};
106static const size_t formatInfosSize = sizeof(formatInfos)/sizeof(FormatInfo);
107
131static const size_t knownFourCCsSize = sizeof(knownFourCCs)/sizeof(Format);
132
134{
136 const char *const name;
137};
138static const FormatName formatNames[] = {
139 { FormatUnknown, "unknown" },
140
141 { FormatR8G8B8, "R8G8B8" },
142 { FormatA8R8G8B8, "A8R8G8B8" },
143 { FormatX8R8G8B8, "X8R8G8B8" },
144 { FormatR5G6B5, "R5G6B5" },
145 { FormatX1R5G5B5, "X1R5G5B5" },
146 { FormatA1R5G5B5, "A1R5G5B5" },
147 { FormatA4R4G4B4, "A4R4G4B4" },
148 { FormatR3G3B2, "R3G3B2" },
149 { FormatA8, "A8" },
150 { FormatA8R3G3B2, "A8R3G3B2" },
151 { FormatX4R4G4B4, "X4R4G4B4" },
152 { FormatA2B10G10R10, "A2B10G10R10" },
153 { FormatA8B8G8R8, "A8B8G8R8" },
154 { FormatX8B8G8R8, "X8B8G8R8" },
155 { FormatG16R16, "G16R16" },
156 { FormatA2R10G10B10, "A2R10G10B10" },
157 { FormatA16B16G16R16, "A16B16G16R16" },
158
159 { FormatA8P8, "A8P8" },
160 { FormatP8, "P8" },
161
162 { FormatL8, "L8" },
163 { FormatA8L8, "A8L8" },
164 { FormatA4L4, "A4L4" },
165
166 { FormatV8U8, "V8U8" },
167 { FormatL6V5U5, "L6V5U5" },
168 { FormatX8L8V8U8, "X8L8V8U8" },
169 { FormatQ8W8V8U8, "Q8W8V8U8" },
170 { FormatV16U16, "V16U16" },
171 { FormatA2W10V10U10, "A2W10V10U10" },
172
173 { FormatUYVY, "UYVY" },
174 { FormatR8G8B8G8, "R8G8_B8G8" },
175 { FormatYUY2, "YUY2" },
176 { FormatG8R8G8B8, "G8R8_G8B8" },
177 { FormatDXT1, "DXT1" },
178 { FormatDXT2, "DXT2" },
179 { FormatDXT3, "DXT3" },
180 { FormatDXT4, "DXT4" },
181 { FormatDXT5, "DXT5" },
182 { FormatRXGB, "RXGB" },
183 { FormatATI2, "ATI2" },
184
185 { FormatD16Lockable, "D16Lockable" },
186 { FormatD32, "D32" },
187 { FormatD15S1, "D15S1" },
188 { FormatD24S8, "D24S8" },
189 { FormatD24X8, "D24X8" },
190 { FormatD24X4S4, "D24X4S4" },
191 { FormatD16, "D16" },
192
193 { FormatD32FLockable, "D32FLockable" },
194 { FormatD24FS8, "D24FS8" },
195
196 { FormatD32Lockable, "D32Lockable" },
197 { FormatS8Lockable, "S8Lockable" },
198
199 { FormatL16, "L16" },
200
201 { FormatVertexData, "VertexData" },
202 { FormatIndex32, "Index32" },
203 { FormatIndex32, "Index32" },
204
205 { FormatQ16W16V16U16, "Q16W16V16U16" },
206
207 { FormatMulti2ARGB8, "Multi2ARGB8" },
208
209 { FormatR16F, "R16F" },
210 { FormatG16R16F, "G16R16F" },
211 { FormatA16B16G16R16F, "A16B16G16R16F" },
212
213 { FormatR32F, "R32F" },
214 { FormatG32R32F, "G32R32F" },
215 { FormatA32B32G32R32F, "A32B32G32R32F" },
216
217 { FormatCxV8U8, "CxV8U8" },
218
219 { FormatA1, "A1" },
220 { FormatA2B10G10R10_XR_BIAS, "A2B10G10R10_XR_BIAS" },
221 { FormatBinaryBuffer, "BinaryBuffer" },
222
223 { FormatP4, "P4" },
224 { FormatA4P4, "A4P4" }
225};
226static const size_t formatNamesSize = sizeof(formatNames)/sizeof(FormatName);
227
228static inline int maskToShift(quint32 mask)
229{
230 if (mask == 0)
231 return 0;
232
233 int result = 0;
234 while (!((mask >> result) & 1))
235 result++;
236 return result;
237}
238
239static inline int maskLength(quint32 mask)
240{
241 int result = 0;
242 while (mask) {
243 if (mask & 1)
244 result++;
245 mask >>= 1;
246 }
247 return result;
248}
249
251{
252 Q_ASSERT(size == 8 || size == 16 || size == 24 || size == 32);
253
254 quint32 value = 0;
255 quint8 tmp;
256 for (unsigned bit = 0; bit < size; bit += 8) {
257 s >> tmp;
258 value += (quint32(tmp) << bit);
259 }
260 return value;
261}
262
263static inline bool hasAlpha(const DDSHeader &dds)
264{
265 return (dds.pixelFormat.flags & (DDSPixelFormat::FlagAlphaPixels | DDSPixelFormat::FlagAlpha)) != 0;
266}
267
268static inline bool isCubeMap(const DDSHeader &dds)
269{
270 return (dds.caps2 & DDSHeader::Caps2CubeMap) != 0;
271}
272
273static inline QRgb yuv2rgb(quint8 Y, quint8 U, quint8 V)
274{
275 return qRgb(quint8(Y + 1.13983 * (V - 128)),
276 quint8(Y - 0.39465 * (U - 128) - 0.58060 * (V - 128)),
277 quint8(Y + 2.03211 * (U - 128)));
278}
279
280static Format getFormat(const DDSHeader &dds)
281{
282 const DDSPixelFormat &format = dds.pixelFormat;
284 return FormatP4;
285 } else if (format.flags & DDSPixelFormat::FlagPaletteIndexed8) {
286 return FormatP8;
287 } else if (format.flags & DDSPixelFormat::FlagFourCC) {
288 for (size_t i = 0; i < knownFourCCsSize; ++i) {
289 if (dds.pixelFormat.fourCC == knownFourCCs[i])
290 return knownFourCCs[i];
291 }
292 } else {
293 for (size_t i = 0; i < formatInfosSize; ++i) {
294 const FormatInfo &info = formatInfos[i];
295 if ((format.flags & info.flags) == info.flags &&
296 format.rgbBitCount == info.bitCount &&
297 format.rBitMask == info.rBitMask &&
298 format.gBitMask == info.gBitMask &&
299 format.bBitMask == info.bBitMask &&
300 format.aBitMask == info.aBitMask) {
301 return info.format;
302 }
303 }
304 }
305
306 return FormatUnknown;
307}
308
310{
311 const double fx = nx / 127.5 - 1.0;
312 const double fy = ny / 127.5 - 1.0;
313 const double fxfy = 1.0 - fx * fx - fy * fy;
314 return fxfy > 0 ? 255 * std::sqrt(fxfy) : 0;
315}
316
318{
319 red = ((color >> 11) & 0x1f) << 3;
320 green = ((color >> 5) & 0x3f) << 2;
321 blue = (color & 0x1f) << 3;
322}
323
324static inline quint8 calcC2(quint8 c0, quint8 c1)
325{
326 return 2.0 * c0 / 3.0 + c1 / 3.0;
327}
328
329static inline quint8 calcC2a(quint8 c0, quint8 c1)
330{
331 return c0 / 2.0 + c1 / 2.0;
332}
333
334static inline quint8 calcC3(quint8 c0, quint8 c1)
335{
336 return c0 / 3.0 + 2.0 * c1 / 3.0;
337}
338
339static void DXTFillColors(QRgb *result, quint16 c0, quint16 c1, quint32 table, bool dxt1a = false)
340{
341 quint8 r[4];
342 quint8 g[4];
343 quint8 b[4];
344 quint8 a[4];
345
346 a[0] = a[1] = a[2] = a[3] = 255;
347
348 decodeColor(c0, r[0], g[0], b[0]);
349 decodeColor(c1, r[1], g[1], b[1]);
350 if (!dxt1a) {
351 r[2] = calcC2(r[0], r[1]);
352 g[2] = calcC2(g[0], g[1]);
353 b[2] = calcC2(b[0], b[1]);
354 r[3] = calcC3(r[0], r[1]);
355 g[3] = calcC3(g[0], g[1]);
356 b[3] = calcC3(b[0], b[1]);
357 } else {
358 r[2] = calcC2a(r[0], r[1]);
359 g[2] = calcC2a(g[0], g[1]);
360 b[2] = calcC2a(b[0], b[1]);
361 r[3] = g[3] = b[3] = a[3] = 0;
362 }
363
364 for (int k = 0; k < 4; k++)
365 for (int l = 0; l < 4; l++) {
366 unsigned index = table & 0x0003;
367 table >>= 2;
368
369 result[k * 4 + l] = qRgba(r[index], g[index], b[index], a[index]);
370 }
371}
372
373template <DXTVersions version>
374inline void setAlphaDXT32Helper(QRgb *rgbArr, quint64 alphas)
375{
376 Q_STATIC_ASSERT(version == Two || version == Three);
377 for (int i = 0; i < 16; i++) {
378 quint8 alpha = 16 * (alphas & 0x0f);
379 QRgb rgb = rgbArr[i];
380 if (version == Two) // DXT2
381 rgbArr[i] = qRgba(qRed(rgb) * alpha / 0xff, qGreen(rgb) * alpha / 0xff, qBlue(rgb) * alpha / 0xff, alpha);
382 else if (version == Three) // DXT3
383 rgbArr[i] = qRgba(qRed(rgb), qGreen(rgb), qBlue(rgb), alpha);
384 alphas = alphas >> 4;
385 }
386}
387
388template <DXTVersions version>
389inline void setAlphaDXT45Helper(QRgb *rgbArr, quint64 alphas)
390{
391 Q_STATIC_ASSERT(version == Four || version == Five);
392 quint8 a[8];
393 a[0] = alphas & 0xff;
394 a[1] = (alphas >> 8) & 0xff;
395 if (a[0] > a[1]) {
396 a[2] = (6*a[0] + 1*a[1]) / 7;
397 a[3] = (5*a[0] + 2*a[1]) / 7;
398 a[4] = (4*a[0] + 3*a[1]) / 7;
399 a[5] = (3*a[0] + 4*a[1]) / 7;
400 a[6] = (2*a[0] + 5*a[1]) / 7;
401 a[7] = (1*a[0] + 6*a[1]) / 7;
402 } else {
403 a[2] = (4*a[0] + 1*a[1]) / 5;
404 a[3] = (3*a[0] + 2*a[1]) / 5;
405 a[4] = (2*a[0] + 3*a[1]) / 5;
406 a[5] = (1*a[0] + 4*a[1]) / 5;
407 a[6] = 0;
408 a[7] = 255;
409 }
410 alphas >>= 16;
411 for (int i = 0; i < 16; i++) {
412 quint8 index = alphas & 0x07;
413 quint8 alpha = a[index];
414 QRgb rgb = rgbArr[i];
415 if (version == Four) // DXT4
416 rgbArr[i] = qRgba(qRed(rgb) * alpha / 0xff, qGreen(rgb) * alpha / 0xff, qBlue(rgb) * alpha / 0xff, alpha);
417 else if (version == Five) // DXT5
418 rgbArr[i] = qRgba(qRed(rgb), qGreen(rgb), qBlue(rgb), alpha);
419 alphas = alphas >> 3;
420 }
421}
422
423template <DXTVersions version>
424inline void setAlphaDXT(QRgb *rgbArr, quint64 alphas)
425{
426 Q_UNUSED(rgbArr);
427 Q_UNUSED(alphas);
428}
429
430template <>
431inline void setAlphaDXT<Two>(QRgb *rgbArr, quint64 alphas)
432{
433 setAlphaDXT32Helper<Two>(rgbArr, alphas);
434}
435
436template <>
437inline void setAlphaDXT<Three>(QRgb *rgbArr, quint64 alphas)
438{
439 setAlphaDXT32Helper<Three>(rgbArr, alphas);
440}
441
442template <>
443inline void setAlphaDXT<Four>(QRgb *rgbArr, quint64 alphas)
444{
445 setAlphaDXT45Helper<Four>(rgbArr, alphas);
446}
447
448template <>
449inline void setAlphaDXT<Five>(QRgb *rgbArr, quint64 alphas)
450{
451 setAlphaDXT45Helper<Five>(rgbArr, alphas);
452}
453
454template <>
455inline void setAlphaDXT<RXGB>(QRgb *rgbArr, quint64 alphas)
456{
457 setAlphaDXT45Helper<Five>(rgbArr, alphas);
458}
459
460static inline QRgb invertRXGBColors(QRgb pixel)
461{
462 return qRgb(qAlpha(pixel), qGreen(pixel), qBlue(pixel));
463}
464
465template <DXTVersions version>
467{
468 QImage::Format format = (version == Two || version == Four) ?
470
472
473 for (quint32 i = 0; i < height; i += 4) {
474 for (quint32 j = 0; j < width; j += 4) {
475 quint64 alpha = 0;
476 quint16 c0, c1;
478 if (version != One)
479 s >> alpha;
480 s >> c0;
481 s >> c1;
482 s >> table;
483
484 QRgb arr[16];
485
486 DXTFillColors(arr, c0, c1, table, version == One && c0 <= c1);
487 setAlphaDXT<version>(arr, alpha);
488
489 const quint32 kMax = qMin<quint32>(4, height - i);
490 const quint32 lMax = qMin<quint32>(4, width - j);
491 for (quint32 k = 0; k < kMax; k++) {
492 QRgb *line = reinterpret_cast<QRgb *>(image.scanLine(i + k));
493 for (quint32 l = 0; l < lMax; l++) {
494 QRgb pixel = arr[k * 4 + l];
495 if (version == RXGB)
496 pixel = invertRXGBColors(pixel);
497
498 line[j + l] = pixel;
499 }
500 }
501 }
502 }
503 return image;
504}
505
507{
508 return readDXT<One>(s, width, height);
509}
510
512{
513 return readDXT<Two>(s, width, height);
514}
515
517{
518 return readDXT<Three>(s, width, height);
519}
520
522{
523 return readDXT<Four>(s, width, height);
524}
525
527{
528 return readDXT<Five>(s, width, height);
529}
530
532{
533 return readDXT<RXGB>(s, width, height);
534}
535
537{
539
540 for (quint32 i = 0; i < height; i += 4) {
541 for (quint32 j = 0; j < width; j += 4) {
542 quint64 alpha1;
543 quint64 alpha2;
544 s >> alpha1;
545 s >> alpha2;
546
547 QRgb arr[16];
548 memset(arr, 0, sizeof(QRgb) * 16);
549 setAlphaDXT<Five>(arr, alpha1);
550 for (int k = 0; k < 16; ++k) {
551 quint8 a = qAlpha(arr[k]);
552 arr[k] = qRgba(0, 0, a, 0);
553 }
554 setAlphaDXT<Five>(arr, alpha2);
555
556 const quint32 kMax = qMin<quint32>(4, height - i);
557 const quint32 lMax = qMin<quint32>(4, width - j);
558 for (quint32 k = 0; k < kMax; k++) {
559 QRgb *line = reinterpret_cast<QRgb *>(image.scanLine(i + k));
560 for (quint32 l = 0; l < lMax; l++) {
561 QRgb pixel = arr[k * 4 + l];
562 const quint8 nx = qAlpha(pixel);
563 const quint8 ny = qBlue(pixel);
564 const quint8 nz = getNormalZ(nx, ny);
565 line[j + l] = qRgb(nx, ny, nz);
566 }
567 }
568 }
569 }
570 return image;
571}
572
574{
575 quint32 flags = dds.pixelFormat.flags;
576
577 quint32 masks[ColorCount];
578 quint8 shifts[ColorCount];
580 masks[Red] = dds.pixelFormat.rBitMask;
581 masks[Green] = dds.pixelFormat.gBitMask;
582 masks[Blue] = dds.pixelFormat.bBitMask;
583 masks[Alpha] = hasAlpha ? dds.pixelFormat.aBitMask : 0;
584 for (int i = 0; i < ColorCount; ++i) {
585 shifts[i] = maskToShift(masks[i]);
586 bits[i] = maskLength(masks[i]);
587
588 // move mask to the left
589 if (bits[i] <= 8)
590 masks[i] = (masks[i] >> shifts[i]) << (8 - bits[i]);
591 }
592
594
596
597 for (quint32 y = 0; y < height; y++) {
598 for (quint32 x = 0; x < width; x++) {
599 QRgb *line = reinterpret_cast<QRgb *>(image.scanLine(y));
600
601 quint32 value = readValue(s, dds.pixelFormat.rgbBitCount);
603
604 for (int c = 0; c < ColorCount; ++c) {
605 if (bits[c] > 8) {
606 // truncate unneseccary bits
607 colors[c] = (value & masks[c]) >> shifts[c] >> (bits[c] - 8);
608 } else {
609 // move color to the left
610 quint8 color = value >> shifts[c] << (8 - bits[c]) & masks[c];
611 if (masks[c])
612 colors[c] = color * 0xff / masks[c];
613 else
614 colors[c] = 0;
615 }
616 }
617
622 else
624 }
625 }
626
627 return image;
628}
629
630static double readFloat16(QDataStream &s)
631{
633 s >> value;
634
635 double sign = (value & 0x8000) == 0x8000 ? -1.0 : 1.0;
636 qint8 exp = (value & 0x7C00) >> 10;
637 quint16 fraction = value & 0x3FF;
638
639 if (exp == 0)
640 return sign * std::pow(2.0, -14.0) * fraction / 1024.0;
641 else
642 return sign * std::pow(2.0, exp - 15) * (1 + fraction / 1024.0);
643}
644
645static inline float readFloat32(QDataStream &s)
646{
647 Q_ASSERT(sizeof(float) == 4);
648 float value;
649 // TODO: find better way to avoid setting precision each time
650 QDataStream::FloatingPointPrecision precision = s.floatingPointPrecision();
651 s.setFloatingPointPrecision(QDataStream::SinglePrecision);
652 s >> value;
653 s.setFloatingPointPrecision(precision);
654 return value;
655}
656
658{
660
661 for (quint32 y = 0; y < height; y++) {
662 QRgb *line = reinterpret_cast<QRgb *>(image.scanLine(y));
663 for (quint32 x = 0; x < width; x++) {
664 quint8 r = readFloat16(s) * 255;
665 line[x] = qRgba(r, 0, 0, 0);
666 }
667 }
668
669 return image;
670}
671
673{
675
676 for (quint32 y = 0; y < height; y++) {
677 QRgb *line = reinterpret_cast<QRgb *>(image.scanLine(y));
678 for (quint32 x = 0; x < width; x++) {
679 quint8 r = readFloat16(s) * 255;
680 quint8 g = readFloat16(s) * 255;
681 line[x] = qRgba(r, g, 0, 0);
682 }
683 }
684
685 return image;
686}
687
689{
691
692 for (quint32 y = 0; y < height; y++) {
693 QRgb *line = reinterpret_cast<QRgb *>(image.scanLine(y));
694 for (quint32 x = 0; x < width; x++) {
696 for (int c = 0; c < ColorCount; ++c)
697 colors[c] = readFloat16(s) * 255;
698
700 }
701 }
702
703 return image;
704}
705
707{
709
710 for (quint32 y = 0; y < height; y++) {
711 QRgb *line = reinterpret_cast<QRgb *>(image.scanLine(y));
712 for (quint32 x = 0; x < width; x++) {
713 quint8 r = readFloat32(s) * 255;
714 line[x] = qRgba(r, 0, 0, 0);
715 }
716 }
717
718 return image;
719}
720
722{
724
725 for (quint32 y = 0; y < height; y++) {
726 QRgb *line = reinterpret_cast<QRgb *>(image.scanLine(y));
727 for (quint32 x = 0; x < width; x++) {
728 quint8 r = readFloat32(s) * 255;
729 quint8 g = readFloat32(s) * 255;
730 line[x] = qRgba(r, g, 0, 0);
731 }
732 }
733
734 return image;
735}
736
738{
740
741 for (quint32 y = 0; y < height; y++) {
742 QRgb *line = reinterpret_cast<QRgb *>(image.scanLine(y));
743 for (quint32 x = 0; x < width; x++) {
745 for (int c = 0; c < ColorCount; ++c)
746 colors[c] = readFloat32(s) * 255;
748 }
749 }
750
751 return image;
752}
753
755{
757
759 qint16 tmp;
760 for (quint32 y = 0; y < height; y++) {
761 QRgb *line = reinterpret_cast<QRgb *>(image.scanLine(y));
762 for (quint32 x = 0; x < width; x++) {
763 for (int i = 0; i < ColorCount; i++) {
764 s >> tmp;
765 colors[i] = (tmp + 0x7FFF) >> 8;
766 }
768 }
769 }
770
771 return image;
772}
773
775{
777
778 for (quint32 y = 0; y < height; y++) {
779 QRgb *line = reinterpret_cast<QRgb *>(image.scanLine(y));
780 for (quint32 x = 0; x < width; x++) {
781 qint8 v, u;
782 s >> v >> u;
783
784 const quint8 vn = v + 128;
785 const quint8 un = u + 128;
786 const quint8 c = getNormalZ(vn, un);
787
788 line[x] = qRgb(vn, un, c);
789 }
790 }
791
792 return image;
793}
794
796{
798 for (int i = 0; i < 256; ++i) {
799 quint8 r, g, b, a;
800 s >> r >> g >> b >> a;
801 image.setColor(i, qRgba(r, g, b, a));
802 }
803
804 for (quint32 y = 0; y < height; y++) {
805 for (quint32 x = 0; x < width; x++) {
807 s >> index;
808 image.setPixel(x, y, index);
809 }
810 }
811
812 return image;
813}
814
816{
818 for (int i = 0; i < 16; ++i) {
819 quint8 r, g, b, a;
820 s >> r >> g >> b >> a;
821 image.setColor(i, qRgba(r, g, b, a));
822 }
823
824 for (quint32 y = 0; y < height; y++) {
826 for (quint32 x = 0; x < width - 1; ) {
827 s >> index;
828 image.setPixel(x++, y, (index & 0x0f) >> 0);
829 image.setPixel(x++, y, (index & 0xf0) >> 4);
830 }
831 if (width % 2 == 1) {
832 s >> index;
833 image.setPixel(width - 1, y, (index & 0x0f) >> 0);
834 }
835 }
836
837 return image;
838}
839
841{
843
844 for (quint32 y = 0; y < height; y++) {
845 QRgb *line = reinterpret_cast<QRgb *>(image.scanLine(y));
846 for (quint32 x = 0; x < width; x++) {
848 for (int i = 0; i < ColorCount; ++i) {
850 s >> color;
851 colors[i] = quint8(color >> 8);
852 }
854 }
855 }
856
857 return image;
858}
859
861{
863
864 for (quint32 y = 0; y < height; y++) {
865 QRgb *line = reinterpret_cast<QRgb *>(image.scanLine(y));
866 for (quint32 x = 0; x < width; x++) {
867 qint8 v, u;
868 s >> v >> u;
869 line[x] = qRgb(v + 128, u + 128, 255);
870 }
871 }
872
873 return image;
874}
875
877{
879
880 quint16 tmp;
881 for (quint32 y = 0; y < height; y++) {
882 QRgb *line = reinterpret_cast<QRgb *>(image.scanLine(y));
883 for (quint32 x = 0; x < width; x++) {
884 s >> tmp;
885 quint8 r = qint8((tmp & 0x001f) >> 0) * 0xff/0x1f + 128;
886 quint8 g = qint8((tmp & 0x03e0) >> 5) * 0xff/0x1f + 128;
887 quint8 b = quint8((tmp & 0xfc00) >> 10) * 0xff/0x3f;
888 line[x] = qRgba(r, g, 0xff, b);
889 }
890 }
891 return image;
892}
893
895{
897
898 quint8 a, l;
899 qint8 v, u;
900 for (quint32 y = 0; y < height; y++) {
901 QRgb *line = reinterpret_cast<QRgb *>(image.scanLine(y));
902 for (quint32 x = 0; x < width; x++) {
903 s >> v >> u >> a >> l;
904 line[x] = qRgba(v + 128, u + 128, 255, a);
905 }
906 }
907
908 return image;
909}
910
912{
914
916 qint8 tmp;
917 for (quint32 y = 0; y < height; y++) {
918 QRgb *line = reinterpret_cast<QRgb *>(image.scanLine(y));
919 for (quint32 x = 0; x < width; x++) {
920 for (int i = 0; i < ColorCount; i++) {
921 s >> tmp;
922 colors[i] = tmp + 128;
923 }
925 }
926 }
927
928 return image;
929}
930
932{
934
935 for (quint32 y = 0; y < height; y++) {
936 QRgb *line = reinterpret_cast<QRgb *>(image.scanLine(y));
937 for (quint32 x = 0; x < width; x++) {
938 qint16 v, u;
939 s >> v >> u;
940 v = (v + 0x8000) >> 8;
941 u = (u + 0x8000) >> 8;
942 line[x] = qRgb(v, u, 255);
943 }
944 }
945
946 return image;
947}
948
950{
952
953 quint32 tmp;
954 for (quint32 y = 0; y < height; y++) {
955 QRgb *line = reinterpret_cast<QRgb *>(image.scanLine(y));
956 for (quint32 x = 0; x < width; x++) {
957 s >> tmp;
958 quint8 r = qint8((tmp & 0x3ff00000) >> 20 >> 2) + 128;
959 quint8 g = qint8((tmp & 0x000ffc00) >> 10 >> 2) + 128;
960 quint8 b = qint8((tmp & 0x000003ff) >> 0 >> 2) + 128;
961 quint8 a = 0xff * ((tmp & 0xc0000000) >> 30) / 3;
962 // dunno why we should swap b and r here
963 std::swap(b, r);
964 line[x] = qRgba(r, g, b, a);
965 }
966 }
967
968 return image;
969}
970
972{
974
975 quint8 uyvy[4];
976 for (quint32 y = 0; y < height; y++) {
977 QRgb *line = reinterpret_cast<QRgb *>(image.scanLine(y));
978 for (quint32 x = 0; x < width - 1; ) {
979 s >> uyvy[0] >> uyvy[1] >> uyvy[2] >> uyvy[3];
980 line[x++] = yuv2rgb(uyvy[1], uyvy[0], uyvy[2]);
981 line[x++] = yuv2rgb(uyvy[3], uyvy[0], uyvy[2]);
982 }
983 if (width % 2 == 1) {
984 s >> uyvy[0] >> uyvy[1] >> uyvy[2] >> uyvy[3];
985 line[width - 1] = yuv2rgb(uyvy[1], uyvy[0], uyvy[2]);
986 }
987 }
988
989 return image;
990}
991
993{
995 quint8 rgbg[4];
996 for (quint32 y = 0; y < height; y++) {
997 QRgb *line = reinterpret_cast<QRgb *>(image.scanLine(y));
998 for (quint32 x = 0; x < width - 1; ) {
999 s >> rgbg[1] >> rgbg[0] >> rgbg[3] >> rgbg[2];
1000 line[x++] = qRgb(rgbg[0], rgbg[1], rgbg[2]);
1001 line[x++] = qRgb(rgbg[0], rgbg[3], rgbg[2]);
1002 }
1003 if (width % 2 == 1) {
1004 s >> rgbg[1] >> rgbg[0] >> rgbg[3] >> rgbg[2];
1005 line[width - 1] = qRgb(rgbg[0], rgbg[1], rgbg[2]);
1006 }
1007 }
1008
1009 return image;
1010}
1011
1013{
1015
1016 quint8 yuyv[4];
1017 for (quint32 y = 0; y < height; y++) {
1018 QRgb *line = reinterpret_cast<QRgb *>(image.scanLine(y));
1019 for (quint32 x = 0; x < width - 1; ) {
1020 s >> yuyv[0] >> yuyv[1] >> yuyv[2] >> yuyv[3];
1021 line[x++] = yuv2rgb(yuyv[0], yuyv[1], yuyv[3]);
1022 line[x++] = yuv2rgb(yuyv[2], yuyv[1], yuyv[3]);
1023 }
1024 if (width % 2 == 1) {
1025 s >> yuyv[0] >> yuyv[1] >> yuyv[2] >> yuyv[3];
1026 line[width - 1] = yuv2rgb(yuyv[2], yuyv[1], yuyv[3]);
1027 }
1028 }
1029
1030 return image;
1031}
1032
1034{
1036 quint8 grgb[4];
1037 for (quint32 y = 0; y < height; y++) {
1038 QRgb *line = reinterpret_cast<QRgb *>(image.scanLine(y));
1039 for (quint32 x = 0; x < width - 1; ) {
1040 s >> grgb[1] >> grgb[0] >> grgb[3] >> grgb[2];
1041 line[x++] = qRgb(grgb[1], grgb[0], grgb[3]);
1042 line[x++] = qRgb(grgb[1], grgb[2], grgb[3]);
1043 }
1044 if (width % 2 == 1) {
1045 s >> grgb[1] >> grgb[0] >> grgb[3] >> grgb[2];
1046 line[width - 1] = qRgb(grgb[1], grgb[0], grgb[3]);
1047 }
1048 }
1049
1050 return image;
1051}
1052
1054{
1055 QImage image = readUnsignedImage(s, dds, width, height, true);
1056 for (quint32 y = 0; y < height; y++) {
1057 QRgb *line = reinterpret_cast<QRgb *>(image.scanLine(y));
1058 for (quint32 x = 0; x < width; x++) {
1059 QRgb pixel = image.pixel(x, y);
1060 line[x] = qRgba(qBlue(pixel), qGreen(pixel), qRed(pixel), qAlpha(pixel));
1061 }
1062 }
1063 return image;
1064}
1065
1067{
1068 if (width * height == 0)
1069 return QImage();
1070
1071 switch (format) {
1072 case FormatR8G8B8:
1073 case FormatX8R8G8B8:
1074 case FormatR5G6B5:
1075 case FormatR3G3B2:
1076 case FormatX1R5G5B5:
1077 case FormatX4R4G4B4:
1078 case FormatX8B8G8R8:
1079 case FormatG16R16:
1080 case FormatL8:
1081 case FormatL16:
1082 return readUnsignedImage(s, dds, width, height, false);
1083 case FormatA8R8G8B8:
1084 case FormatA1R5G5B5:
1085 case FormatA4R4G4B4:
1086 case FormatA8:
1087 case FormatA8R3G3B2:
1088 case FormatA8B8G8R8:
1089 case FormatA8L8:
1090 case FormatA4L4:
1091 return readUnsignedImage(s, dds, width, height, true);
1092 case FormatA2R10G10B10:
1093 case FormatA2B10G10R10:
1094 return readA2R10G10B10(s, dds, width, height);
1095 case FormatP8:
1096 case FormatA8P8:
1097 return readPalette8Image(s, width, height);
1098 case FormatP4:
1099 case FormatA4P4:
1100 return readPalette4Image(s, width, height);
1101 case FormatA16B16G16R16:
1102 return readARGB16(s, width, height);
1103 case FormatV8U8:
1104 return readV8U8(s, width, height);
1105 case FormatL6V5U5:
1106 return readL6V5U5(s, width, height);
1107 case FormatX8L8V8U8:
1108 return readX8L8V8U8(s, width, height);
1109 case FormatQ8W8V8U8:
1110 return readQ8W8V8U8(s, width, height);
1111 case FormatV16U16:
1112 return readV16U16(s, width, height);
1113 case FormatA2W10V10U10:
1114 return readA2W10V10U10(s, width, height);
1115 case FormatUYVY:
1116 return readUYVY(s, width, height);
1117 case FormatR8G8B8G8:
1118 return readR8G8B8G8(s, width, height);
1119 case FormatYUY2:
1120 return readYUY2(s, width, height);
1121 case FormatG8R8G8B8:
1122 return readG8R8G8B8(s, width, height);
1123 case FormatDXT1:
1124 return readDXT1(s, width, height);
1125 case FormatDXT2:
1126 return readDXT2(s, width, height);
1127 case FormatDXT3:
1128 return readDXT3(s, width, height);
1129 case FormatDXT4:
1130 return readDXT4(s, width, height);
1131 case FormatDXT5:
1132 return readDXT5(s, width, height);
1133 case FormatRXGB:
1134 return readRXGB(s, width, height);
1135 case FormatATI2:
1136 return readATI2(s, width, height);
1137 case FormatR16F:
1138 return readR16F(s, width, height);
1139 case FormatG16R16F:
1140 return readRG16F(s, width, height);
1142 return readARGB16F(s, width, height);
1143 case FormatR32F:
1144 return readR32F(s, width, height);
1145 case FormatG32R32F:
1146 return readRG32F(s, width, height);
1148 return readARGB32F(s, width, height);
1149 case FormatD16Lockable:
1150 case FormatD32:
1151 case FormatD15S1:
1152 case FormatD24S8:
1153 case FormatD24X8:
1154 case FormatD24X4S4:
1155 case FormatD16:
1156 case FormatD32FLockable:
1157 case FormatD24FS8:
1158 case FormatD32Lockable:
1159 case FormatS8Lockable:
1160 case FormatVertexData:
1161 case FormatIndex16:
1162 case FormatIndex32:
1163 break;
1164 case FormatQ16W16V16U16:
1165 return readQ16W16V16U16(s, width, height);
1166 case FormatMulti2ARGB8:
1167 break;
1168 case FormatCxV8U8:
1169 return readCxV8U8(s, width, height);
1170 case FormatA1:
1172 case FormatBinaryBuffer:
1173 case FormatLast:
1174 break;
1175 }
1176
1177 return QImage();
1178}
1179
1180static inline QImage readTexture(QDataStream &s, const DDSHeader &dds, const int format, const int mipmapLevel)
1181{
1182 quint32 width = dds.width / (1 << mipmapLevel);
1183 quint32 height = dds.height / (1 << mipmapLevel);
1184 return readLayer(s, dds, format, width, height);
1185}
1186
1187static qint64 mipmapSize(const DDSHeader &dds, const int format, const int level)
1188{
1189 quint32 w = dds.width/(1 << level);
1190 quint32 h = dds.height/(1 << level);
1191
1192 switch (format) {
1193 case FormatR8G8B8:
1194 case FormatX8R8G8B8:
1195 case FormatR5G6B5:
1196 case FormatX1R5G5B5:
1197 case FormatX4R4G4B4:
1198 case FormatX8B8G8R8:
1199 case FormatG16R16:
1200 case FormatL8:
1201 case FormatL16:
1202 return w * h * dds.pixelFormat.rgbBitCount / 8;
1203 case FormatA8R8G8B8:
1204 case FormatA1R5G5B5:
1205 case FormatA4R4G4B4:
1206 case FormatA8:
1207 case FormatA8R3G3B2:
1208 case FormatA2B10G10R10:
1209 case FormatA8B8G8R8:
1210 case FormatA2R10G10B10:
1211 case FormatA8L8:
1212 case FormatA4L4:
1213 return w * h * dds.pixelFormat.rgbBitCount / 8;
1214 case FormatP8:
1215 return 256 + w * h * 8;
1216 case FormatA16B16G16R16:
1217 return w * h * 4 * 2;
1218 case FormatA8P8:
1219 break;
1220 case FormatV8U8:
1221 case FormatL6V5U5:
1222 return w * h * 2;
1223 case FormatX8L8V8U8:
1224 case FormatQ8W8V8U8:
1225 case FormatV16U16:
1226 case FormatA2W10V10U10:
1227 return w * h * 4;
1228 case FormatUYVY:
1229 case FormatR8G8B8G8:
1230 case FormatYUY2:
1231 case FormatG8R8G8B8:
1232 return w * h * 2;
1233 case FormatDXT1:
1234 return ((w + 3)/4) * ((h + 3)/4) * 8;
1235 case FormatDXT2:
1236 case FormatDXT3:
1237 case FormatDXT4:
1238 case FormatDXT5:
1239 return ((w + 3)/4) * ((h + 3)/4) * 16;
1240 case FormatD16Lockable:
1241 case FormatD32:
1242 case FormatD15S1:
1243 case FormatD24S8:
1244 case FormatD24X8:
1245 case FormatD24X4S4:
1246 case FormatD16:
1247 case FormatD32FLockable:
1248 case FormatD24FS8:
1249 case FormatD32Lockable:
1250 case FormatS8Lockable:
1251 case FormatVertexData:
1252 case FormatIndex16:
1253 case FormatIndex32:
1254 break;
1255 case FormatQ16W16V16U16:
1256 return w * h * 4 * 2;
1257 case FormatMulti2ARGB8:
1258 break;
1259 case FormatR16F:
1260 return w * h * 1 * 2;
1261 case FormatG16R16F:
1262 return w * h * 2 * 2;
1264 return w * h * 4 * 2;
1265 case FormatR32F:
1266 return w * h * 1 * 4;
1267 case FormatG32R32F:
1268 return w * h * 2 * 4;
1270 return w * h * 4 * 4;
1271 case FormatCxV8U8:
1272 return w * h * 2;
1273 case FormatA1:
1275 case FormatBinaryBuffer:
1276 case FormatLast:
1277 break;
1278 }
1279
1280 return 0;
1281}
1282
1283static qint64 mipmapOffset(const DDSHeader &dds, const int format, const int level)
1284{
1285 qint64 result = 0;
1286 for (int i = 0; i < level; ++i)
1287 result += mipmapSize(dds, format, i);
1288 return result;
1289}
1290
1291static QImage readCubeMap(QDataStream &s, const DDSHeader &dds, const int fmt)
1292{
1294 QImage image(4 * dds.width, 3 * dds.height, format);
1295
1296 image.fill(0);
1297
1298 for (int i = 0; i < 6; i++) {
1299 if (!(dds.caps2 & faceFlags[i]))
1300 continue; // Skip face.
1301
1302 const QImage face = readLayer(s, dds, fmt, dds.width, dds.height);
1303
1304 // Compute face offsets.
1305 int offset_x = faceOffsets[i].x * dds.width;
1306 int offset_y = faceOffsets[i].y * dds.height;
1307
1308 // Copy face on the image.
1309 for (quint32 y = 0; y < dds.height; y++) {
1310 const QRgb *src = reinterpret_cast<const QRgb *>(face.scanLine(y));
1311 QRgb *dst = reinterpret_cast<QRgb *>(image.scanLine(y + offset_y)) + offset_x;
1312 memcpy(dst, src, sizeof(QRgb) * dds.width);
1313 }
1314 }
1315
1316 return image;
1317}
1318
1320{
1321 for (size_t i = 0; i < formatNamesSize; ++i) {
1322 if (formatNames[i].format == format)
1323 return formatNames[i].name;
1324 }
1325
1326 return formatNames[0].name;
1327}
1328
1329static int formatByName(const QByteArray &name)
1330{
1331 const QByteArray loweredName = name.toLower();
1332 for (size_t i = 0; i < formatNamesSize; ++i) {
1333 if (QByteArray(formatNames[i].name).toLower() == loweredName)
1334 return formatNames[i].format;
1335 }
1336
1337 return FormatUnknown;
1338}
1339
1341 m_header(),
1342 m_format(FormatA8R8G8B8),
1343 m_header10(),
1344 m_currentImage(0),
1345 m_scanState(ScanNotScanned)
1346{
1347}
1348
1350{
1351 if (m_scanState == ScanNotScanned && !canRead(device()))
1352 return false;
1353
1354 if (m_scanState != ScanError) {
1356 return true;
1357 }
1358
1359 return false;
1360}
1361
1363{
1364 if (!ensureScanned() || device()->isSequential())
1365 return false;
1366
1367 qint64 pos = headerSize + mipmapOffset(m_header, m_format, m_currentImage);
1368 if (!device()->seek(pos))
1369 return false;
1370 QDataStream s(device());
1371 s.setByteOrder(QDataStream::LittleEndian);
1372
1373 QImage image = isCubeMap(m_header) ?
1374 readCubeMap(s, m_header, m_format) :
1375 readTexture(s, m_header, m_format, m_currentImage);
1376
1377 bool ok = s.status() == QDataStream::Ok && !image.isNull();
1378 if (ok)
1379 *outImage = image;
1380 return ok;
1381}
1382
1383bool QDDSHandler::write(const QImage &outImage)
1384{
1385 if (m_format != FormatA8R8G8B8) {
1386 qWarning() << "Format" << formatName(m_format) << "is not supported";
1387 return false;
1388 }
1389
1390 const QImage image = outImage.convertToFormat(QImage::Format_ARGB32);
1391
1392 QDataStream s(device());
1393 s.setByteOrder(QDataStream::LittleEndian);
1394
1395 DDSHeader dds;
1396 // Filling header
1397 dds.magic = ddsMagic;
1398 dds.size = 124;
1401 dds.height = image.height();
1402 dds.width = image.width();
1403 dds.pitchOrLinearSize = 128;
1404 dds.depth = 0;
1405 dds.mipMapCount = 0;
1406 for (int i = 0; i < DDSHeader::ReservedCount; i++)
1407 dds.reserved1[i] = 0;
1408 dds.caps = DDSHeader::CapsTexture;
1409 dds.caps2 = 0;
1410 dds.caps3 = 0;
1411 dds.caps4 = 0;
1412 dds.reserved2 = 0;
1413
1414 // Filling pixelformat
1415 dds.pixelFormat.size = 32;
1417 dds.pixelFormat.fourCC = 0;
1418 dds.pixelFormat.rgbBitCount = 32;
1419 dds.pixelFormat.aBitMask = 0xff000000;
1420 dds.pixelFormat.rBitMask = 0x00ff0000;
1421 dds.pixelFormat.gBitMask = 0x0000ff00;
1422 dds.pixelFormat.bBitMask = 0x000000ff;
1423
1424 s << dds;
1425 for (int height = 0; height < image.height(); height++) {
1426 for (int width = 0; width < image.width(); width++) {
1427 QRgb pixel = image.pixel(width, height);
1428 quint32 color;
1429 quint8 alpha = qAlpha(pixel);
1430 quint8 red = qRed(pixel);
1431 quint8 green = qGreen(pixel);
1432 quint8 blue = qBlue(pixel);
1433 color = (alpha << 24) + (red << 16) + (green << 8) + blue;
1434 s << color;
1435 }
1436 }
1437
1438 return true;
1439}
1440
1442{
1443 if (!supportsOption(option) || !ensureScanned())
1444 return QVariant();
1445
1446 switch (option) {
1448 return QSize(m_header.width, m_header.height);
1450 return formatName(m_format);
1452 return QVariant::fromValue(QList<QByteArray>() << formatName(FormatA8R8G8B8));
1453 default:
1454 break;
1455 }
1456
1457 return QVariant();
1458}
1459
1461{
1463 const QByteArray subType = value.toByteArray();
1464 m_format = formatByName(subType.toUpper());
1465 if (m_format == FormatUnknown)
1466 qWarning() << "unknown format" << subType;
1467 }
1468}
1469
1476
1478{
1479 if (!ensureScanned())
1480 return 0;
1481
1482 return qMax<quint32>(1, m_header.mipMapCount);
1483}
1484
1485bool QDDSHandler::jumpToImage(int imageNumber)
1486{
1487 if (imageNumber >= imageCount())
1488 return false;
1489
1490 m_currentImage = imageNumber;
1491 return true;
1492}
1493
1495{
1496 if (!device) {
1497 qWarning() << "DDSHandler::canRead() called with no device";
1498 return false;
1499 }
1500
1501 if (device->isSequential())
1502 return false;
1503
1504 return device->peek(4) == QByteArrayLiteral("DDS ");
1505}
1506
1507bool QDDSHandler::ensureScanned() const
1508{
1509 if (m_scanState != ScanNotScanned)
1510 return m_scanState == ScanSuccess;
1511
1512 m_scanState = ScanError;
1513
1514 QDDSHandler *that = const_cast<QDDSHandler *>(this);
1515 that->m_format = FormatUnknown;
1516
1517 if (device()->isSequential()) {
1518 qWarning() << "Sequential devices are not supported";
1519 return false;
1520 }
1521
1522 qint64 oldPos = device()->pos();
1523 device()->seek(0);
1524
1525 QDataStream s(device());
1526 s.setByteOrder(QDataStream::LittleEndian);
1527 s >> that->m_header;
1528 if (m_header.pixelFormat.fourCC == dx10Magic)
1529 s >> that->m_header10;
1530
1531 device()->seek(oldPos);
1532
1533 if (s.status() != QDataStream::Ok)
1534 return false;
1535
1536 if (!verifyHeader(m_header))
1537 return false;
1538
1539 that->m_format = getFormat(m_header);
1540 if (that->m_format == FormatUnknown)
1541 return false;
1542
1543 m_scanState = ScanSuccess;
1544 return true;
1545}
1546
1547bool QDDSHandler::verifyHeader(const DDSHeader &dds) const
1548{
1549 quint32 flags = dds.flags;
1552 if ((flags & requiredFlags) != requiredFlags) {
1553 qWarning() << "Wrong dds.flags - not all required flags present. "
1554 "Actual flags :" << flags;
1555 return false;
1556 }
1557
1558 if (dds.size != ddsSize) {
1559 qWarning() << "Wrong dds.size: actual =" << dds.size
1560 << "expected =" << ddsSize;
1561 return false;
1562 }
1563
1564 if (dds.pixelFormat.size != pixelFormatSize) {
1565 qWarning() << "Wrong dds.pixelFormat.size: actual =" << dds.pixelFormat.size
1566 << "expected =" << pixelFormatSize;
1567 return false;
1568 }
1569
1570 if (dds.width > INT_MAX || dds.height > INT_MAX) {
1571 qWarning() << "Can't read image with w/h bigger than INT_MAX";
1572 return false;
1573 }
1574
1575 return true;
1576}
1577
1579
1580#endif // QT_NO_DATASTREAM
IOBluetoothDevice * device
\inmodule QtCore
Definition qbytearray.h:57
QByteArray toUpper() const &
Definition qbytearray.h:258
QByteArray toLower() const &
Definition qbytearray.h:254
bool canRead() const override
Returns true if an image can be read from the device (i.e., the image format is supported,...
QVariant option(QImageIOHandler::ImageOption option) const override
Returns the value assigned to option as a QVariant.
int imageCount() const override
For image formats that support animation, this function returns the number of images in the animation...
void setOption(ImageOption option, const QVariant &value) override
Sets the option option with the value value.
bool read(QImage *image) override
Read an image from the device, and stores it in image.
bool jumpToImage(int imageNumber) override
For image formats that support animation, this function jumps to the image whose sequence number is i...
bool supportsOption(QImageIOHandler::ImageOption option) const override
Returns true if the QImageIOHandler supports the option option; otherwise returns false.
bool write(const QImage &image) override
Writes the image image to the assigned device.
\inmodule QtCore\reentrant
Definition qdatastream.h:46
\inmodule QtCore \reentrant
Definition qiodevice.h:34
virtual qint64 pos() const
For random-access devices, this function returns the position that data is written to or read from.
virtual bool isSequential() const
Returns true if this device is sequential; otherwise returns false.
qint64 peek(char *data, qint64 maxlen)
virtual bool seek(qint64 pos)
For random-access devices, this function sets the current position to pos, returning true on success,...
ImageOption
This enum describes the different options supported by QImageIOHandler.
QIODevice * device() const
Returns the device currently assigned to the QImageIOHandler.
void setFormat(const QByteArray &format)
Sets the format of the QImageIOHandler to format.
\inmodule QtGui
Definition qimage.h:37
Format
The following image formats are available in Qt.
Definition qimage.h:41
@ Format_RGB32
Definition qimage.h:46
@ Format_Indexed8
Definition qimage.h:45
@ Format_ARGB32_Premultiplied
Definition qimage.h:48
@ Format_ARGB32
Definition qimage.h:47
\inmodule QtCore
Definition qsize.h:25
\inmodule QtCore
Definition qvariant.h:65
static auto fromValue(T &&value) noexcept(std::is_nothrow_copy_constructible_v< T > &&Private::CanUseInternalSpace< T >) -> std::enable_if_t< std::conjunction_v< std::is_copy_constructible< T >, std::is_destructible< T > >, QVariant >
Definition qvariant.h:536
Format
Definition ddsheader.h:14
@ FormatA32B32G32R32F
Definition ddsheader.h:91
@ FormatD24FS8
Definition ddsheader.h:70
@ FormatUnknown
Definition ddsheader.h:15
@ FormatA4P4
Definition ddsheader.h:100
@ FormatD24X4S4
Definition ddsheader.h:66
@ FormatUYVY
Definition ddsheader.h:49
@ FormatRXGB
Definition ddsheader.h:58
@ FormatX4R4G4B4
Definition ddsheader.h:27
@ FormatA8R3G3B2
Definition ddsheader.h:26
@ FormatR8G8B8G8
Definition ddsheader.h:50
@ FormatA8
Definition ddsheader.h:25
@ FormatP4
Definition ddsheader.h:99
@ FormatA1
Definition ddsheader.h:95
@ FormatA8P8
Definition ddsheader.h:35
@ FormatX8B8G8R8
Definition ddsheader.h:30
@ FormatIndex32
Definition ddsheader.h:79
@ FormatA8R8G8B8
Definition ddsheader.h:18
@ FormatP8
Definition ddsheader.h:36
@ FormatA2B10G10R10_XR_BIAS
Definition ddsheader.h:96
@ FormatS8Lockable
Definition ddsheader.h:73
@ FormatMulti2ARGB8
Definition ddsheader.h:83
@ FormatCxV8U8
Definition ddsheader.h:93
@ FormatDXT4
Definition ddsheader.h:56
@ FormatA2W10V10U10
Definition ddsheader.h:47
@ FormatDXT5
Definition ddsheader.h:57
@ FormatR8G8B8
Definition ddsheader.h:17
@ FormatL8
Definition ddsheader.h:38
@ FormatV8U8
Definition ddsheader.h:42
@ FormatG16R16F
Definition ddsheader.h:86
@ FormatDXT3
Definition ddsheader.h:55
@ FormatA4R4G4B4
Definition ddsheader.h:23
@ FormatD32Lockable
Definition ddsheader.h:72
@ FormatA16B16G16R16
Definition ddsheader.h:33
@ FormatLast
Definition ddsheader.h:102
@ FormatDXT2
Definition ddsheader.h:54
@ FormatD32
Definition ddsheader.h:62
@ FormatD16
Definition ddsheader.h:67
@ FormatX1R5G5B5
Definition ddsheader.h:21
@ FormatR32F
Definition ddsheader.h:89
@ FormatQ16W16V16U16
Definition ddsheader.h:81
@ FormatV16U16
Definition ddsheader.h:46
@ FormatA2B10G10R10
Definition ddsheader.h:28
@ FormatG16R16
Definition ddsheader.h:31
@ FormatA16B16G16R16F
Definition ddsheader.h:87
@ FormatATI2
Definition ddsheader.h:59
@ FormatD16Lockable
Definition ddsheader.h:61
@ FormatQ8W8V8U8
Definition ddsheader.h:45
@ FormatA4L4
Definition ddsheader.h:40
@ FormatA2R10G10B10
Definition ddsheader.h:32
@ FormatD32FLockable
Definition ddsheader.h:69
@ FormatL6V5U5
Definition ddsheader.h:43
@ FormatG8R8G8B8
Definition ddsheader.h:52
@ FormatG32R32F
Definition ddsheader.h:90
@ FormatD24S8
Definition ddsheader.h:64
@ FormatR5G6B5
Definition ddsheader.h:20
@ FormatX8L8V8U8
Definition ddsheader.h:44
@ FormatX8R8G8B8
Definition ddsheader.h:19
@ FormatVertexData
Definition ddsheader.h:77
@ FormatYUY2
Definition ddsheader.h:51
@ FormatD24X8
Definition ddsheader.h:65
@ FormatR3G3B2
Definition ddsheader.h:24
@ FormatA1R5G5B5
Definition ddsheader.h:22
@ FormatBinaryBuffer
Definition ddsheader.h:97
@ FormatL16
Definition ddsheader.h:75
@ FormatIndex16
Definition ddsheader.h:78
@ FormatD15S1
Definition ddsheader.h:63
@ FormatR16F
Definition ddsheader.h:85
@ FormatA8B8G8R8
Definition ddsheader.h:29
@ FormatDXT1
Definition ddsheader.h:53
@ FormatA8L8
Definition ddsheader.h:39
Combined button and popup list for selecting options.
Definition image.cpp:4
#define Q_STATIC_ASSERT(Condition)
Definition qassert.h:108
#define QByteArrayLiteral(str)
Definition qbytearray.h:52
#define rgb(r, g, b)
Definition qcolor.cpp:124
static const size_t formatInfosSize
static quint8 calcC3(quint8 c0, quint8 c1)
DXTVersions
@ Three
@ Four
@ Two
@ RXGB
@ One
@ Five
static QImage readUYVY(QDataStream &s, quint32 width, quint32 height)
static bool isCubeMap(const DDSHeader &dds)
static double readFloat16(QDataStream &s)
static QImage readQ16W16V16U16(QDataStream &s, const quint32 width, const quint32 height)
static QImage readR32F(QDataStream &s, const quint32 width, const quint32 height)
static QImage readPalette4Image(QDataStream &s, quint32 width, quint32 height)
static quint8 calcC2a(quint8 c0, quint8 c1)
static QImage readYUY2(QDataStream &s, quint32 width, quint32 height)
static QImage readDXT4(QDataStream &s, quint32 width, quint32 height)
static QImage readR16F(QDataStream &s, const quint32 width, const quint32 height)
static QImage readDXT(QDataStream &s, quint32 width, quint32 height)
static QImage readDXT1(QDataStream &s, quint32 width, quint32 height)
static QImage readLayer(QDataStream &s, const DDSHeader &dds, const int format, quint32 width, quint32 height)
static const FaceOffset faceOffsets[6]
void setAlphaDXT< Four >(QRgb *rgbArr, quint64 alphas)
static QImage readCxV8U8(QDataStream &s, const quint32 width, const quint32 height)
static QImage readTexture(QDataStream &s, const DDSHeader &dds, const int format, const int mipmapLevel)
void setAlphaDXT< RXGB >(QRgb *rgbArr, quint64 alphas)
static QImage readDXT3(QDataStream &s, quint32 width, quint32 height)
void setAlphaDXT45Helper(QRgb *rgbArr, quint64 alphas)
static QImage readRG32F(QDataStream &s, const quint32 width, const quint32 height)
static int maskLength(quint32 mask)
Colors
@ Alpha
@ Green
@ Red
@ ColorCount
@ Blue
static QImage readDXT2(QDataStream &s, quint32 width, quint32 height)
static QImage readARGB32F(QDataStream &s, const quint32 width, const quint32 height)
static quint32 readValue(QDataStream &s, quint32 size)
static QImage readRG16F(QDataStream &s, const quint32 width, const quint32 height)
static QImage readATI2(QDataStream &s, quint32 width, quint32 height)
static QRgb yuv2rgb(quint8 Y, quint8 U, quint8 V)
static QImage readRXGB(QDataStream &s, quint32 width, quint32 height)
static QImage readR8G8B8G8(QDataStream &s, quint32 width, quint32 height)
static QImage readA2R10G10B10(QDataStream &s, const DDSHeader &dds, quint32 width, quint32 height)
static qint64 mipmapOffset(const DDSHeader &dds, const int format, const int level)
static int formatByName(const QByteArray &name)
static const quint32 dx10Magic
static QImage readUnsignedImage(QDataStream &s, const DDSHeader &dds, quint32 width, quint32 height, bool hasAlpha)
static Format getFormat(const DDSHeader &dds)
static const quint32 ddsMagic
void setAlphaDXT< Five >(QRgb *rgbArr, quint64 alphas)
static QImage readX8L8V8U8(QDataStream &s, quint32 width, quint32 height)
static float readFloat32(QDataStream &s)
static QImage readV8U8(QDataStream &s, quint32 width, quint32 height)
void setAlphaDXT< Two >(QRgb *rgbArr, quint64 alphas)
static QImage readL6V5U5(QDataStream &s, quint32 width, quint32 height)
static int maskToShift(quint32 mask)
static QImage readARGB16(QDataStream &s, quint32 width, quint32 height)
static const qint64 headerSize
static QImage readARGB16F(QDataStream &s, const quint32 width, const quint32 height)
static const quint32 ddsSize
static QImage readA2W10V10U10(QDataStream &s, quint32 width, quint32 height)
static QImage readQ8W8V8U8(QDataStream &s, quint32 width, quint32 height)
void setAlphaDXT< Three >(QRgb *rgbArr, quint64 alphas)
static const quint32 pixelFormatSize
static const Format knownFourCCs[]
static QImage readV16U16(QDataStream &s, quint32 width, quint32 height)
static void decodeColor(quint16 color, quint8 &red, quint8 &green, quint8 &blue)
static QImage readG8R8G8B8(QDataStream &s, quint32 width, quint32 height)
static QByteArray formatName(int format)
static void DXTFillColors(QRgb *result, quint16 c0, quint16 c1, quint32 table, bool dxt1a=false)
static QImage readDXT5(QDataStream &s, quint32 width, quint32 height)
static qint64 mipmapSize(const DDSHeader &dds, const int format, const int level)
static bool hasAlpha(const DDSHeader &dds)
static quint8 getNormalZ(quint8 nx, quint8 ny)
static QImage readCubeMap(QDataStream &s, const DDSHeader &dds, const int fmt)
static quint8 calcC2(quint8 c0, quint8 c1)
void setAlphaDXT(QRgb *rgbArr, quint64 alphas)
static QRgb invertRXGBColors(QRgb pixel)
static int faceFlags[6]
static const FormatInfo formatInfos[]
static QImage readPalette8Image(QDataStream &s, quint32 width, quint32 height)
static const FormatName formatNames[]
void setAlphaDXT32Helper(QRgb *rgbArr, quint64 alphas)
static const size_t formatNamesSize
static const size_t knownFourCCsSize
typedef QByteArray(EGLAPIENTRYP PFNQGSGETDISPLAYSPROC)()
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
#define qWarning
Definition qlogging.h:166
GLboolean GLboolean GLboolean b
GLsizei const GLfloat * v
[13]
GLint GLint GLint GLint GLint x
[0]
GLenum GLuint GLint level
GLfloat GLfloat GLfloat w
[0]
GLint GLsizei GLsizei height
GLboolean GLboolean GLboolean GLboolean a
[7]
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLuint index
[2]
GLboolean r
[2]
GLenum face
GLenum src
GLint GLsizei width
GLuint color
[2]
GLenum GLenum dst
GLbitfield flags
GLboolean GLboolean g
GLuint name
GLint GLint GLint GLint GLint GLint GLint GLbitfield mask
GLint GLsizei GLsizei GLenum format
GLint y
GLfloat GLfloat GLfloat GLfloat h
GLdouble s
[6]
Definition qopenglext.h:235
GLfixed GLfixed nz
GLbyte GLbyte blue
Definition qopenglext.h:385
GLbyte nx
const GLubyte * c
GLfixed ny
GLenum GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const void * bits
GLuint64EXT * result
[6]
GLuint GLenum option
GLfloat GLfloat GLfloat alpha
Definition qopenglext.h:418
GLbyte green
Definition qopenglext.h:385
GLenum GLenum GLsizei void * table
GLenum GLint GLint * precision
static QT_BEGIN_NAMESPACE const QRgb colors[][14]
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
QT_BEGIN_NAMESPACE typedef unsigned int QRgb
Definition qrgb.h:13
constexpr QRgb qRgb(int r, int g, int b)
Definition qrgb.h:30
constexpr int qRed(QRgb rgb)
Definition qrgb.h:18
constexpr int qGreen(QRgb rgb)
Definition qrgb.h:21
constexpr QRgb qRgba(int r, int g, int b, int a)
Definition qrgb.h:33
constexpr int qBlue(QRgb rgb)
Definition qrgb.h:24
constexpr int qAlpha(QRgb rgb)
Definition qrgb.h:27
#define Q_UNUSED(x)
unsigned int quint32
Definition qtypes.h:50
short qint16
Definition qtypes.h:47
unsigned short quint16
Definition qtypes.h:48
unsigned long long quint64
Definition qtypes.h:61
long long qint64
Definition qtypes.h:60
QT_BEGIN_NAMESPACE typedef signed char qint8
Definition qtypes.h:45
unsigned char quint8
Definition qtypes.h:46
QVideoFrameFormat::PixelFormat fmt
static int sign(int x)
QHostInfo info
[0]
QGraphicsSvgItem * red
quint32 mipMapCount
Definition ddsheader.h:173
@ ReservedCount
Definition ddsheader.h:164
@ Caps2CubeMapPositiveY
Definition ddsheader.h:157
@ Caps2CubeMapPositiveX
Definition ddsheader.h:155
@ Caps2CubeMapNegativeX
Definition ddsheader.h:156
@ Caps2CubeMapPositiveZ
Definition ddsheader.h:159
@ Caps2CubeMapNegativeZ
Definition ddsheader.h:160
@ Caps2CubeMapNegativeY
Definition ddsheader.h:158
DDSPixelFormat pixelFormat
Definition ddsheader.h:175
quint32 height
Definition ddsheader.h:169
quint32 magic
Definition ddsheader.h:166
@ FlagPixelFormat
Definition ddsheader.h:141
quint32 width
Definition ddsheader.h:170
quint32 fourCC
Definition ddsheader.h:123
quint32 bBitMask
quint32 bitCount
quint32 gBitMask
Format format
quint32 flags
quint32 aBitMask
quint32 rBitMask
const char *const name