mirror of
https://invent.kde.org/frameworks/kimageformats.git
synced 2025-05-28 00:30:23 -04:00
TGA: added options support
Code aligned with KF6 (MR !210) to mitigate CCBUG: 413801 and CCBUG: 479612 - Added Size and Format options support - Fixed a double image allocation when reading RGBA images (RGB was always allocated and then replaced by RGBA one) - Fixed the code for sequential devices
This commit is contained in:
parent
7cc4cb8d0c
commit
f5962442ca
@ -88,10 +88,6 @@ static QDataStream &operator>>(QDataStream &s, TgaHeader &head)
|
|||||||
s >> head.height;
|
s >> head.height;
|
||||||
s >> head.pixel_size;
|
s >> head.pixel_size;
|
||||||
s >> head.flags;
|
s >> head.flags;
|
||||||
/*qDebug() << "id_length: " << head.id_length << " - colormap_type: " << head.colormap_type << " - image_type: " << head.image_type;
|
|
||||||
qDebug() << "colormap_index: " << head.colormap_index << " - colormap_length: " << head.colormap_length << " - colormap_size: " << head.colormap_size;
|
|
||||||
qDebug() << "x_origin: " << head.x_origin << " - y_origin: " << head.y_origin << " - width:" << head.width << " - height:" << head.height << " - pixelsize:
|
|
||||||
" << head.pixel_size << " - flags: " << head.flags;*/
|
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -174,10 +170,57 @@ struct TgaHeaderInfo {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static QImage::Format imageFormat(const TgaHeader &head)
|
||||||
|
{
|
||||||
|
auto format = QImage::Format_Invalid;
|
||||||
|
if (IsSupported(head)) {
|
||||||
|
// Bits 0-3 are the numbers of alpha bits (can be zero!)
|
||||||
|
const int numAlphaBits = head.flags & 0xf;
|
||||||
|
// However alpha exists only in the 32 bit format.
|
||||||
|
if ((head.pixel_size == 32) && (head.flags & 0xf)) {
|
||||||
|
if (numAlphaBits <= 8) {
|
||||||
|
format = QImage::Format_ARGB32;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
format = QImage::Format_RGB32;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return format;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief peekHeader
|
||||||
|
* Reads the header but does not change the position in the device.
|
||||||
|
*/
|
||||||
|
static bool peekHeader(QIODevice *device, TgaHeader &header)
|
||||||
|
{
|
||||||
|
qint64 oldPos = device->pos();
|
||||||
|
QByteArray head = device->read(TgaHeader::SIZE);
|
||||||
|
int readBytes = head.size();
|
||||||
|
|
||||||
|
if (device->isSequential()) {
|
||||||
|
for (int pos = readBytes - 1; pos >= 0; --pos) {
|
||||||
|
device->ungetChar(head[pos]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
device->seek(oldPos);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (readBytes < TgaHeader::SIZE) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QDataStream stream(head);
|
||||||
|
stream.setByteOrder(QDataStream::LittleEndian);
|
||||||
|
stream >> header;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static bool LoadTGA(QDataStream &s, const TgaHeader &tga, QImage &img)
|
static bool LoadTGA(QDataStream &s, const TgaHeader &tga, QImage &img)
|
||||||
{
|
{
|
||||||
// Create image.
|
img = imageAlloc(tga.width, tga.height, imageFormat(tga));
|
||||||
img = imageAlloc(tga.width, tga.height, QImage::Format_RGB32);
|
|
||||||
if (img.isNull()) {
|
if (img.isNull()) {
|
||||||
qWarning() << "Failed to allocate image, invalid dimensions?" << QSize(tga.width, tga.height);
|
qWarning() << "Failed to allocate image, invalid dimensions?" << QSize(tga.width, tga.height);
|
||||||
return false;
|
return false;
|
||||||
@ -185,21 +228,7 @@ static bool LoadTGA(QDataStream &s, const TgaHeader &tga, QImage &img)
|
|||||||
|
|
||||||
TgaHeaderInfo info(tga);
|
TgaHeaderInfo info(tga);
|
||||||
|
|
||||||
// Bits 0-3 are the numbers of alpha bits (can be zero!)
|
|
||||||
const int numAlphaBits = tga.flags & 0xf;
|
const int numAlphaBits = tga.flags & 0xf;
|
||||||
// However alpha exists only in the 32 bit format.
|
|
||||||
if ((tga.pixel_size == 32) && (tga.flags & 0xf)) {
|
|
||||||
img = imageAlloc(tga.width, tga.height, QImage::Format_ARGB32);
|
|
||||||
if (img.isNull()) {
|
|
||||||
qWarning() << "Failed to allocate image, invalid dimensions?" << QSize(tga.width, tga.height);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (numAlphaBits > 8) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint pixel_size = (tga.pixel_size / 8);
|
uint pixel_size = (tga.pixel_size / 8);
|
||||||
qint64 size = qint64(tga.width) * qint64(tga.height) * pixel_size;
|
qint64 size = qint64(tga.width) * qint64(tga.height) * pixel_size;
|
||||||
|
|
||||||
@ -395,23 +424,25 @@ bool TGAHandler::read(QImage *outImage)
|
|||||||
{
|
{
|
||||||
// qDebug() << "Loading TGA file!";
|
// qDebug() << "Loading TGA file!";
|
||||||
|
|
||||||
QDataStream s(device());
|
auto d = device();
|
||||||
s.setByteOrder(QDataStream::LittleEndian);
|
|
||||||
|
|
||||||
// Read image header.
|
|
||||||
TgaHeader tga;
|
TgaHeader tga;
|
||||||
s >> tga;
|
if (!peekHeader(d, tga) || !IsSupported(tga)) {
|
||||||
s.device()->seek(TgaHeader::SIZE + tga.id_length);
|
|
||||||
|
|
||||||
// Check image file format.
|
|
||||||
if (s.atEnd()) {
|
|
||||||
// qDebug() << "This TGA file is not valid.";
|
// qDebug() << "This TGA file is not valid.";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check supported file types.
|
if (d->isSequential()) {
|
||||||
if (!IsSupported(tga)) {
|
d->read(TgaHeader::SIZE + tga.id_length);
|
||||||
// qDebug() << "This TGA file is not supported.";
|
} else {
|
||||||
|
d->seek(TgaHeader::SIZE + tga.id_length);
|
||||||
|
}
|
||||||
|
|
||||||
|
QDataStream s(d);
|
||||||
|
s.setByteOrder(QDataStream::LittleEndian);
|
||||||
|
|
||||||
|
// Check image file format.
|
||||||
|
if (s.atEnd()) {
|
||||||
|
// qDebug() << "This TGA file is not valid.";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -472,6 +503,42 @@ bool TGAHandler::write(const QImage &image)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool TGAHandler::supportsOption(ImageOption option) const
|
||||||
|
{
|
||||||
|
if (option == QImageIOHandler::Size) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (option == QImageIOHandler::ImageFormat) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant TGAHandler::option(ImageOption option) const
|
||||||
|
{
|
||||||
|
QVariant v;
|
||||||
|
|
||||||
|
if (option == QImageIOHandler::Size) {
|
||||||
|
if (auto d = device()) {
|
||||||
|
TgaHeader header;
|
||||||
|
if (peekHeader(d, header) && IsSupported(header)) {
|
||||||
|
v = QVariant::fromValue(QSize(header.width, header.height));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (option == QImageIOHandler::ImageFormat) {
|
||||||
|
if (auto d = device()) {
|
||||||
|
TgaHeader header;
|
||||||
|
if (peekHeader(d, header) && IsSupported(header)) {
|
||||||
|
v = QVariant::fromValue(imageFormat(header));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
bool TGAHandler::canRead(QIODevice *device)
|
bool TGAHandler::canRead(QIODevice *device)
|
||||||
{
|
{
|
||||||
if (!device) {
|
if (!device) {
|
||||||
@ -495,10 +562,12 @@ bool TGAHandler::canRead(QIODevice *device)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
QDataStream stream(head);
|
|
||||||
stream.setByteOrder(QDataStream::LittleEndian);
|
|
||||||
TgaHeader tga;
|
TgaHeader tga;
|
||||||
stream >> tga;
|
if (!peekHeader(device, tga)) {
|
||||||
|
qWarning("TGAHandler::canRead() error while reading the header");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return IsSupported(tga);
|
return IsSupported(tga);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,6 +19,9 @@ public:
|
|||||||
bool read(QImage *image) override;
|
bool read(QImage *image) override;
|
||||||
bool write(const QImage &image) override;
|
bool write(const QImage &image) override;
|
||||||
|
|
||||||
|
bool supportsOption(QImageIOHandler::ImageOption option) const override;
|
||||||
|
QVariant option(QImageIOHandler::ImageOption option) const override;
|
||||||
|
|
||||||
static bool canRead(QIODevice *device);
|
static bool canRead(QIODevice *device);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user