Question

I am looking to display heightmaps from the video game Battlefield 2 as images in my application.
I am new to C++ and Qt and it might be straight forward but what I am having trouble with is displaying a grayscale 16-bit 1025x1025 2101250 bytes image. There is no header to the file. I need access to the displayed pixels (does not have to be pixel perfect precision) so I can point to a pixel and get its value.

What I have tried

I have loaded the binary data into a QByteArray from a QFile and I have attempted to use the QImage::fromData function to make the image but I am making a lot of mistakes and spending a lot of time not getting very far. It is my hope that posting here will give me the clue(s) that I need to progress. Here is my code:

void LearningBinaryReader::setupReader()
{
    qDebug("Attempting to open file..");
    QFile file("HeightmapPrimary.raw");
    if (!file.open(QFile::ReadOnly))
    {
        qDebug("Could not open file");
        return;
    } else {
        qDebug() << file.fileName() << " opened";
    }
    QByteArray data = file.readAll();
    file.flush();
    file.close();

    qDebug() << data.count() << "bytes loaded.";
}

From here I am at a loss of what to do. I have read some of the Qt documentation, but I being new I need a guide in the right direction to understand this problem and get the solution.

Please note I am pretty much a beginner so don't discount easy solutions that I might not have thought of. I would like to do this just using the Qt framework.

Était-ce utile?

La solution

Just a guess. Maybe try something like this?

#include <QColor>
...
QByteArray data=file.readAll();

// create an empty image of the right size.  We'll use 32-bit RGB for simplicity
QImage img(1025,1025, QImage::Format_RGB32);

// Access the image at low level.  From the manual, a 32-bit RGB image is just a
// vector of QRgb (which is really just some integer typedef)
QRgb *pixels=reinterpret_cast<QRgb*>(img.bits());

// Now copy our image data in.  We'll assume 16-bit LE format for the input data.
// Since we only have 8 bits of grayscale color resolution in a 32-bit RGB, we'll
// just chop off the most significant 8 bits (the second byte of each pair) and 
// make a pixel out of that.  If this doesn't work, our assumption might be off --
// perhaps assume 16-bit BE format.  In that case we'd want the first byte of each
// pair.
for (size_t i=0;2*i<data.size();++i)
{
    uchar pixel_msb=data[2*i+1]; // or maybe try =data[2*i+0]
    pixels[i]=qRgb(pixel_msb, pixel_msb, pixel_msb);
}

// (do something with the resulting 'img')

edit: oops, QImage::Format_RGB32 instead of QImage::Format_RGB

Autres conseils

You cannot use loadFromData, because it does not support raw (see Reading and Writing Image Files).

You can't find 16bit raw in supported format so I think the best solution is using a converter between the image loading and the image displaying.

Create a new QImage, with a format supported by qt.

QImage* image = new QImage(1025, 1025, QImage::Format_RGB888);

Then load the source image and convert it to RGB888. Your image is very big, so avoid loading it all with readAll(). You can use this simple converter (see below) or a converter from an existing library (like Magick++).

QFile file("HeightmapPrimary.raw");
if (!file.open(QFile::ReadOnly))
{
    qDebug("Could not open file");
    return;
}
uint16_t buf;
uchar* dst = image->bits();
while (readData(&buf, 2)) {
  dst[0] = buf / 256; /* from 16bit to 8bit */
  dst[1] = buf / 256;
  dst[2] = buf / 256;
  dst += 3; /* next pixel */
}

1. Basically what you need to do is to draw your pixels inside a widget.

So, firstly create an application which has a dialog, then draw on the dialog using the recommendations from:

Qt4 How to draw inside a widget?

And for the QPainter documentation: http://qt-project.org/doc/qt-4.8/QPainter.html

Notice, that you will need to create a QBrush while going through the pixels: http://doc.qt.nokia.com/4.7/qbrush.html

This will be pretty slow :(

2. Another more advanced solution would be to create a QImageReader and an associated Image IO plugin to read your format ( http://qt-project.org/doc/qt-4.8/qimagereader.html ) then create a QPixMap with the image reader ( http://qt-project.org/doc/qt-4.8/qpixmap.html#fromImageReader ) and create a QBrush with the given QPixmap and use it to draw :)

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top