Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Toggle main menu visibility
Loading...
Searching...
No Matches
qtgafile.cpp
Go to the documentation of this file.
1
// Copyright (C) 2016 The Qt Company Ltd.
2
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
// Qt-Security score:critical reason:data-parser
4
5
#
include
"qtgafile.h"
6
7
#
include
<
QtCore
/
QIODevice
>
8
#
include
<
QtCore
/
QDebug
>
9
#
include
<
QtCore
/
QDateTime
>
10
#
include
<
QtGui
/
QImageIOHandler
>
11
12
namespace
{
13
14
struct
TgaReader
15
{
16
Q_DISABLE_COPY(TgaReader)
17
18
TgaReader() =
default
;
19
20
virtual
~TgaReader() {}
21
virtual
QRgb operator()(QIODevice *s)
const
= 0;
22
};
23
24
struct
Tga16Reader :
public
TgaReader
25
{
26
~Tga16Reader() {}
27
QRgb operator()(QIODevice *s)
const
override
28
{
29
char
ch1, ch2;
30
if
(s->getChar(&ch1) && s->getChar(&ch2)) {
31
quint16 d = (
int
(ch1) & 0xFF) | ((
int
(ch2) & 0xFF) << 8);
32
QRgb result = (d & 0x8000) ? 0xFF000000 : 0x00000000;
33
result |= ((d & 0x7C00) << 6) | ((d & 0x03E0) << 3) | (d & 0x001F);
34
return
result;
35
}
else
{
36
return
0;
37
}
38
}
39
};
40
41
struct
Tga24Reader :
public
TgaReader
42
{
43
QRgb operator()(QIODevice *s)
const
override
44
{
45
char
r, g, b;
46
if
(s->getChar(&b) && s->getChar(&g) && s->getChar(&r))
47
return
qRgb(uchar(r), uchar(g), uchar(b));
48
else
49
return
0;
50
}
51
};
52
53
struct
Tga32Reader :
public
TgaReader
54
{
55
QRgb operator()(QIODevice *s)
const
override
56
{
57
char
r, g, b, a;
58
if
(s->getChar(&b) && s->getChar(&g) && s->getChar(&r) && s->getChar(&a))
59
return
qRgba(uchar(r), uchar(g), uchar(b), uchar(a));
60
else
61
return
0;
62
}
63
};
64
65
}
// namespace
66
67
/*!
68
\class QTgaFile
69
\since 4.8
70
\internal
71
72
File data container for a TrueVision Graphics format file.
73
74
Format is as described here:
75
http://local.wasp.uwa.edu.au/~pbourke/dataformats/tga/
76
http://netghost.narod.ru/gff2/graphics/summary/tga.htm
77
78
Usage is:
79
\code
80
QTgaFile tga(myFile);
81
QImage tgaImage;
82
if (tga.isValid())
83
tgaImage = tga.readImage();
84
\endcode
85
86
The class is designed to handle sequential and non-sequential
87
sources, so during construction the mHeader is read. Then during
88
the readImage() call the rest of the data is read.
89
90
After passing myFile to the constructor, if the QIODevice *myFile
91
is read, or has seek() called, the results are undefined - so don't
92
do that.
93
*/
94
95
/*!
96
Construct a new QTgaFile object getting data from \a device.
97
98
The object does not take ownership of the \a device, but until the
99
object is destroyed do not do any non-const operations, eg seek or
100
read on the device.
101
*/
102
QTgaFile
::
QTgaFile
(QIODevice *device)
103
: mDevice(device)
104
{
105
::memset(mHeader, 0, HeaderSize);
106
if
(!mDevice->isReadable())
107
{
108
mErrorMessage = tr(
"Could not read image data"
);
109
return
;
110
}
111
if
(mDevice->isSequential())
112
{
113
mErrorMessage = tr(
"Sequential device (eg socket) for image read not supported"
);
114
return
;
115
}
116
if
(!mDevice->seek(0))
117
{
118
mErrorMessage = tr(
"Seek file/device for image read failed"
);
119
return
;
120
}
121
if
(device->read(
reinterpret_cast
<
char
*>(mHeader),
HeaderSize
) !=
HeaderSize
) {
122
mErrorMessage = tr(
"Image header read failed"
);
123
return
;
124
}
125
if
(mHeader[
ImageType
] != 2)
126
{
127
// TODO: should support other image types
128
mErrorMessage = tr(
"Image type not supported"
);
129
return
;
130
}
131
int
bitsPerPixel = mHeader[
PixelDepth
];
132
bool
validDepth = (bitsPerPixel == 16 || bitsPerPixel == 24 || bitsPerPixel == 32);
133
if
(!validDepth)
134
{
135
mErrorMessage = tr(
"Image depth not valid"
);
136
return
;
137
}
138
if
(quint64(
width
(
)
) * quint64(
height
(
)
) > (8192 * 8192))
139
{
140
mErrorMessage = tr(
"Image size exceeds limit"
);
141
return
;
142
}
143
}
144
145
/*!
146
\internal
147
Destroy the device, recovering any resources.
148
*/
149
QTgaFile
::~
QTgaFile
()
150
{
151
}
152
153
/*!
154
\internal
155
Reads an image file from the QTgaFile's device, and returns it.
156
157
This method seeks to the absolute position of the image data in the file,
158
so no assumptions are made about where the devices read pointer is when this
159
method is called. For this reason only random access devices are supported.
160
161
If the constructor completed successfully, such that isValid() returns true,
162
then this method is likely to succeed, unless the file is somehow corrupted.
163
164
In the case that the read fails, the QImage returned will be null, such that
165
QImage::isNull() will be true.
166
*/
167
QImage
QTgaFile
::
readImage
()
168
{
169
if
(!
isValid
(
)
)
170
return
QImage();
171
172
int
offset = mHeader[
IdLength
];
// Mostly always zero
173
174
// Even in TrueColor files a color palette may be present so we have to check it here
175
// even we only support image type 2 (= uncompressed true-color image)
176
if
(mHeader[
ColorMapType
] == 1) {
177
int
cmapDepth = mHeader[
CMapDepth
];
178
if
(cmapDepth == 15)
// 15 bit is stored as 16 bit + ignoring the highest bit (no alpha)
179
cmapDepth = 16;
180
if
(cmapDepth != 16 && cmapDepth != 24 && cmapDepth != 32) {
181
mErrorMessage = tr(
"Invalid color map depth (%1)"
).arg(cmapDepth);
182
return
{};
183
}
184
offset += littleEndianInt(&mHeader[CMapLength]) * cmapDepth / 8;
185
}
186
187
mDevice->seek(
HeaderSize
+ offset);
188
189
int
bitsPerPixel = mHeader[
PixelDepth
];
190
int
imageWidth =
width
(
)
;
191
int
imageHeight =
height
(
)
;
192
193
unsigned
char
desc = mHeader[
ImageDescriptor
];
194
//unsigned char xCorner = desc & 0x10; // 0 = left, 1 = right
195
unsigned
char
yCorner = desc & 0x20;
// 0 = lower, 1 = upper
196
197
const
qint64 pixelDataSize = qint64(imageWidth) * imageHeight * (bitsPerPixel / 8);
198
if
(mDevice->size() > 0 && mDevice->size() - mDevice->pos() < pixelDataSize) {
199
mErrorMessage = tr(
"Insufficient image data for declared image size"
);
200
return
{};
201
}
202
203
QImage im;
204
if
(!QImageIOHandler::allocateImage(QSize(imageWidth, imageHeight), QImage::Format_ARGB32, &im))
205
return
QImage();
206
TgaReader *reader = 0;
207
if
(bitsPerPixel == 16)
208
reader =
new
Tga16Reader();
209
else
if
(bitsPerPixel == 24)
210
reader =
new
Tga24Reader();
211
else
if
(bitsPerPixel == 32)
212
reader =
new
Tga32Reader();
213
else
214
return
QImage();
215
TgaReader &read = *reader;
216
217
// For now only deal with yCorner, since no one uses xCorner == 1
218
// Also this is upside down, since Qt has the origin flipped
219
if
(yCorner)
220
{
221
for
(
int
y = 0; y < imageHeight; ++y)
222
for
(
int
x = 0; x < imageWidth; ++x)
223
im.setPixel(x, y, read(mDevice));
224
}
225
else
226
{
227
for
(
int
y = imageHeight - 1; y >= 0; --y)
228
for
(
int
x = 0; x < imageWidth; ++x)
229
im.setPixel(x, y, read(mDevice));
230
}
231
232
delete
reader;
233
234
// TODO: add processing of TGA extension information - ie TGA 2.0 files
235
return
im;
236
}
QTgaFile
Definition
qtgafile.h:17
QTgaFile::isValid
bool isValid() const
Definition
qtgafile.h:70
QTgaFile::width
int width() const
Definition
qtgafile.h:99
QTgaFile::QTgaFile
QTgaFile(QIODevice *)
Construct a new QTgaFile object getting data from device.
Definition
qtgafile.cpp:102
QTgaFile::height
int height() const
Definition
qtgafile.h:104
QTgaFile::ColorMapType
@ ColorMapType
Definition
qtgafile.h:28
QTgaFile::CMapDepth
@ CMapDepth
Definition
qtgafile.h:32
QTgaFile::IdLength
@ IdLength
Definition
qtgafile.h:27
QTgaFile::ImageDescriptor
@ ImageDescriptor
Definition
qtgafile.h:38
QTgaFile::PixelDepth
@ PixelDepth
Definition
qtgafile.h:37
QTgaFile::HeaderSize
@ HeaderSize
Definition
qtgafile.h:39
QTgaFile::ImageType
@ ImageType
Definition
qtgafile.h:29
QTgaFile::~QTgaFile
~QTgaFile()
Definition
qtgafile.cpp:149
QTgaFile::readImage
QImage readImage()
Definition
qtgafile.cpp:167
qtimageformats
src
plugins
imageformats
tga
qtgafile.cpp
Generated on
for Qt by
1.18.0