I am trying to read a TGA file header with Qt QDataStream. I have the following structure from the specs with fixed types:
#pragma pack(push, 1)
/* TGA header */
struct tga_header_t
{
quint8 id_lenght; /* size of image id */
quint8 colormap_type; /* 1 is has a colormap */
quint8 image_type; /* compression type */
/* Color Map Specification */
quint16 cm_origin; /* colormap origin */
quint16 cm_length; /* colormap length */
quint8 cm_size; /* colormap size */
/* Image Specification */
quint16 x_origin; /* bottom left x coord origin */
quint16 y_origin; /* bottom left y coord origin */
quint16 width; /* picture width (in pixels) */
quint16 height; /* picture height (in pixels) */
quint8 pixel_depth; /* bits per pixel: 8, 16, 24 or 32 */
quint8 image_descriptor; /* 24 bits = 0x00; 32 bits = 0x80 */
};
#pragma pack(pop)
I open a file with QFile then construct a QDataStream with it as such:
QFile file(path);
tga_header_t header;
file.open(QIODevice::ReadOnly);
QDataStream stream(&file);
stream >> header.id_lenght >>
header.colormap_type >>
header.image_type >>
header.cm_origin >>
header.cm_length >>
header.cm_size >>
header.x_origin >>
header.y_origin >>
header.width >>
header.height >>
header.pixel_depth >>
header.image_descriptor;
qDebug() << header.id_lenght << "id_lenght" <<
header.colormap_type << "colormap_type" <<
header.image_type << "image_type" <<
header.cm_origin << "cm_origin" <<
header.cm_length << "cm_length" <<
header.cm_size << "cm_size" <<
header.x_origin << "x_origin" <<
header.y_origin << "y_origin" <<
header.width << "width" <<
header.height << "height" <<
header.pixel_depth << "pixel_depth" <<
header.image_descriptor << "image_descriptor" <<
"SIZE:" << sizeof(header);
The problem is with width and height I get :
0 id_lenght 0 colormap_type 2 image_type 0 cm_origin 0 cm_length 0 cm_size 0 x_origin 0 y_origin 22021 width 3 height 24 pixel_depth 0 image_descriptor SIZE: 18
And I should get 1366 and 768. If I hexdump the file I get :
0000000 0000 0002 0000 0000 0000 0000 0556 0300
0000010 0018 0000 0000 0000 0000 0000 0000 0000
Which is weird because it has an extra byte at the start and another missing somewhere between 0x0002
and 0x0556
.
Update:
Using fstream works, so correct me if I am wrong but I think the <<
operator does not work as I expect it to (read only the size necessary to fill the struct variable).
stream.read((char*)&header.id_lenght, sizeof(header.id_lenght));
stream.read((char*)&header.colormap_type, sizeof(header.colormap_type));
stream.read((char*)&header.image_type, sizeof(header.image_type));
stream.read((char*)&header.cm_origin, sizeof(header.cm_origin));
stream.read((char*)&header.cm_length, sizeof(header.cm_length));
stream.read((char*)&header.cm_size, sizeof(header.cm_size));
stream.read((char*)&header.x_origin, sizeof(header.x_origin));
stream.read((char*)&header.y_origin, sizeof(header.y_origin));
stream.read((char*)&header.width, sizeof(header.width));
stream.read((char*)&header.height, sizeof(header.height));
stream.read((char*)&header.pixel_depth, sizeof(header.pixel_depth));
stream.read((char*)&header.image_descriptor, sizeof(header.image_descriptor));
Using QDataStream::readRawData also works:
stream.readRawData((char*)&header.id_lenght, sizeof(header.id_lenght));
stream.readRawData((char*)&header.colormap_type, sizeof(header.colormap_type));
stream.readRawData((char*)&header.image_type, sizeof(header.image_type));
stream.readRawData((char*)&header.cm_origin, sizeof(header.cm_origin));
stream.readRawData((char*)&header.cm_length, sizeof(header.cm_length));
stream.readRawData((char*)&header.cm_size, sizeof(header.cm_size));
stream.readRawData((char*)&header.x_origin, sizeof(header.x_origin));
stream.readRawData((char*)&header.y_origin, sizeof(header.y_origin));
stream.readRawData((char*)&header.width, sizeof(header.width));
stream.readRawData((char*)&header.height, sizeof(header.height));
stream.readRawData((char*)&header.pixel_depth, sizeof(header.pixel_depth));
stream.readRawData((char*)&header.image_descriptor, sizeof(header.image_descriptor));
The data is OK. Your PC interprets 16-bit words as little-endian. In the file they are stored as big endians.
For all 16-bit types you should swap low/high bytes. You also could use the helper functions from Qt: http://doc.qt.io/qt-4.8/qtendian.html