PDA

View Full Version : Creating a pixmap from unsigned char*



winder
11th February 2010, 13:06
Helllo :)

i want to dispaly an image in my app, which i manually constructed using a table of unsigned *char. The format is RGBRGBRGB...... and so on... (I don't need alpha)

here is a sample code i used to write for a similar wxWidgets application:




int size = m_Width * m_Height * 3;
unsigned char *img;
img = (unsigned char*) malloc (size);
int j = 0;

for(int i=0; i<m_Width * m_Height; i++)
{
img[j] = m_Grey8Data[i];
img[j+1] = m_Grey8Data[i];
img[j+2] = m_Grey8Data[i];
j += 3;
}



Is there a way i can create a pixmap out of this array? If not, what technique should i use to achieve the same thing?

Thanks in advance

high_flyer
11th February 2010, 13:30
did you try QPixmap::loadFromData() ?

winder
11th February 2010, 14:44
yes but this function requires the data to contain headers. Only supports formats like bmp, jpg.. etc

high_flyer
11th February 2010, 15:01
the functions does not require a header, it will resort to searching for one if the format is not given.
I have used it many times with raw data with out a header.
From what you have written in the first post, I would try "BMP" or "PPM" if the function did not guess correctly with out a specified format.

winder
11th February 2010, 18:42
here is the code i ended up with:


uint iWidth = 640;
uint iHeight = 480;
uint iSize = iWidth * iHeight;
uchar *imgData = new uchar[iSize*4];
uint j=0;
for(uint i=0; i<iSize; i++)
{
imgData[j] = 255; // R
imgData[j+1] = 128; // G
imgData[j+2] = 128; // B
imgData[j+3] = 255; // A
j += 4;
}
QImage image(iWidth, iHeight, QImage::Format_ARGB32);

for (unsigned int y = 0; y < iHeight; y++)
{
for(unsigned int x = 0; x < iWidth; x++)
{
int s = y*iWidth + x*4;
QColor color(imgData[s], imgData[s+1], imgData[s+2], imgData[s+3]);
image.setPixel(x, y, color.rgba());
}
}

m_pm = new QPixmap();
*m_pm = m_pm->fromImage(image);


It works as expected. I'm not sure though if everything is done correctly. Please comment on the above code :)

thanks

high_flyer
12th February 2010, 08:58
Yes, for manipulating image data QImage is the way to go.
However, this code generates a uniform image, for that you don't need all that code, unless this is only a test code.
Tip: If you need to change an already existing image, you can use QImage::bits() to access the image data, so you don't need to allocate and delete and call setPixel() size times for each change.

mhoover
26th July 2010, 21:58
I wish I knew a way to use your above code with QPixmap::loadFromData instead of the QImage version since it costs to much CPU time for me to convert back to the pixmap for display.

For some reason the function always fails for me and returns a null QPixmap.

I'm doing something like:


char *the_image[ 64 * 64 ];
for (int i = 0; i < (64 * 64); i++ ) {
the_image[ i ] = qrand() % 256;
}
my_pixmap.loadFromData( the_image, 64 * 64 );

But loadFromData always returns 0 (fail).

Any tips?

ChrisW67
27th July 2010, 00:23
I really would look at generating a PPM (http://netpbm.sourceforge.net/doc/ppm.html) "file". It is very similar to your RGB bytes with a few simple headers specifying colour depth, height, width preceding it. Here's a basic example:


#include <QtGui>
#include <QDebug>

class mainwindow: public QMainWindow {
public:
mainwindow(QWidget *p = 0): QMainWindow(p) {
makeImage(256, 256, 255);
QLabel *widget = new QLabel(this);
widget->setPixmap(m_pixmap);
setCentralWidget(widget);
}
private:
void makeImage(int width, int height, int maxColour) {
QByteArray ba;
bool goodLoad;

// Header
ba.append("P6 ");
ba.append(QString::number(width).toAscii());
ba.append(" ");
ba.append(QString::number(height).toAscii());
ba.append(" ");
ba.append(QString::number(maxColour).toAscii());
ba.append("\n");

// Raw binary data
for (int r = 0; r < height; r++) {
for (int c = 0; c < width; c++) {
ba.append( char(r % maxColour) ); // red byte (use 16 bits if maxColour > 255)
ba.append( char(r % maxColour) ); // green byte
ba.append( char(r % maxColour) ); // blue byte
}
}
goodLoad = m_pixmap.loadFromData(ba, "ppm");
qDebug() << goodLoad;
}

QPixmap m_pixmap;
};

int main(int argc, char *argv[])
{
QApplication app(argc, argv);
mainwindow m;
m.show();
return app.exec();
}

mhoover
27th July 2010, 02:54
Thanks ChrisW67!

This code worked great. I found that when I wanted to actually display my video data, it helped to change the file format a little bit to a PGM file (it's grayscale and doesn't expect an R a G and a B for every pixel). This involved basically just setting the P6 in the header to P5 and then appending my char* data.

I had expected that replacing my QImage->QPixmap code to direct QPixmap code would reduce my %cpu substantially, but it is very similar. It actually uses 4%cpu more. This is after an optimization I did where I made the QByteArray a member variable and used QByteArray::replace() instead of QByteArrayAppend() (that optimization shaved 26%cpu off my application).

Thanks for your help.

Wolf4D
6th July 2021, 13:56
Sorry for posting in such an old theme - but you have an error in line 20.
It should be

int s = y*iWidth*4 + x*4;
or it won't work properly.