What is meant by bytesPerLine in QImage? - qt

What is mean by bytesPerLine in
QImage::QImage ( uchar * data, int width, int height, int bytesPerLine, Format format )
In documentation it is mentioned as bytesPerLine specifies the number of bytes per line (stride).
I am not clear with its usage. Are width and bytesPerLine the same? Could anyone please explain it?

bytesperline means the number of bytes required by the image pixels in a given row.
to illustrate this consider the following code snippet...
int imageWidth = 800;
int imageHeight = 600;
int bytesPerPixel = 4; // 4 for RGBA, 3 for RGB
int format = QImage::Format_ARGB32; // this is the pixel format - check Qimage::Format enum type for more options
QImage image(yourData, imageWidth, imageHeight, imageWidth * bytesPerPixel, format);

Related

QImage data alignment

The documentation of
QImage::QImage(uchar *data, int width, int height, Format format, QImageCleanupFunction cleanupFunction = Q_NULLPTR, void *cleanupInfo = Q_NULLPTR)
describes that the data, refered by parameter 'data', must be 32 bit aligned. http://doc.qt.io/qt-5/qimage.html#QImage-3 But it's at least unclear what is meant exactly. I assume, each pixel takes 32 bits. But that is not the case. Constructing an image like this is working:
uint8_t* rgb = new uint8_t[3 * height * width];
QImage Img(rgb, width, height, QImage::Format_RGB888);
But this is confusing. When I want to get the pixel values from the image, I thought I need to do this (since the data is 32 bit aligned and Qrgb is 32 bit):
QRgb*rawPixelData = (QRgb*) Img.bits();
for(uint32_t i = 0; i < (Img.width * Img.height); ++i)
{
qDebug() << "Red" << qRed(rawPixelData[i]);
qDebug() << "Green" << qGreen(rawPixelData[i]);
qDebug() << "Blue" << qBlue(rawPixelData[i]);
}
But this is not working (leads to a crash). So, I assume, the data is not 32bit aligned. So, isn't the data 32 bit aligned, or I'm understanding something wrong?
I assume that by the "data" they mean the array of bytes used. And by alignment they mean that the first byte of the array would be 32bit aligned and thus data % 4 would always be 0. It is not the internal alignment of every pixel, just the alignment of the memory block that contains the pixel data.
Furthermore, bits() returns a pointer to an unsigned byte, not a pointer to a QRgb. A QRgb is essentially just an integer:
typedef unsigned int QRgb;
I suspect you are getting a crash because the raw data is "compacted". Meaning that if your image has only RGB and no alpha, it will use only 24bits or 3 bytes per pixel, because that would eliminate a 25% memory usage overhead. As a result, you are walking off the actual data and getting a crash.
You should try iterating it as w * h * 3 unsigned chars and incrementing by 3 for each next pixel, and your rgb would be respectively the bytes at i, i+1, i+2.
It could probably work if your image format was RGBA.
And indeed if you bother to check the byteCount you'd realize that the amount of bytes used internally are the minimum amount for a given format:
QImage img(100, 100, QImage::Format_RGB888);
qDebug() << img.byteCount(); // 30000 or 3 bytes or 24 bits
QImage img2(100, 100, QImage::Format_RGB555);
qDebug() << img2.byteCount(); // 20000 or 2 bytes or 15 bits
QImage img3(100, 100, QImage::Format_RGBA8888);
qDebug() << img3.byteCount(); // 40000 or 4 bytes or 32 bits
But it's at least unclear what is meant exactly.
The expression is part of the software engineering vernacular and has nothing to do with the specific situation at hand: it doesn't have anything to do with Qt nor images nor pixels.
On platforms where Qt is supported, it has the following strict meaning:
uchar *data = ...;
Q_ASSERT(reinterpret_cast<uintptr_t>(data) & 3 == 0);
Or, on an arbitrary C++17 platform, it has the following strict meaning:
size_t size = ...;
uchar *data = ...;
Q_ASSERT(std::align(4, size, reinterpret_cast<void*&>(data), size) ==
reinterpret_cast<void*>(data));

using glDrawPixels to render bitmap raw data

I receive raw image data from server. The server uses MS Dib() function which returns in BGR format. Now, what i want to do is to read this raw data and use glDrawPixels to draw it in Linux.
I was advised that GetClrTabAddress function in MS and alike shall be used to get me the RGB values for each index of 800 by 600 image sent to me.
I do not know how to get these values using indices. Could anyone give some tips.
void func(QByteArray)
{
window_width = 800;
window_height = 600;
size = window_width * window_height;
pixels = new float[size*3];
memcpy(pixels, bytes, bytes.size());
}
void GlWidget::paintGL()
{
//! [5]
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glDrawPixels(window_width,window_height,GL_RGB,GL_FLOAT,pixels);
}
You can use GL_BGR in glDrawPixels, which will do the conversion for you and will probably be faster since AFAIK the GPU will do the work.
QByteArray sounds like you should be using unsigned bytes/chars instead of floats, which means GL_UNSIGNED_BYTE.
I'd assert(size*3*sizeof(float) == bytes.size());.
In this case make sure to set glPixelStorei(GL_UNPACK_ALIGNMENT, 1) if your width doesn't align to the default 4-byte boundry. With GL_BGR very pixel is 3 bytes and by default each row of your pixels is assumed to be padded to the next 4-byte boundary.
[EDIT]
OK, it looks like the image uses a palette. This means every value inthe QByteArray maps to an rgb value in another array. I'm not 100% sure where the palette is and maybe it can be computed implicitly, but you mentioned GetClrTabAddress which sounds promising.
The code will then look something like this
for(int i = 0; i < size; ++i)
{
unsigned char index = btmp[i];
//and something like..
memcpy(bytes + i * 3, GetClrTabAddress() + index * 3, 3);
//or
bytes[i*3+0] = someOtherPaletteData[index].red;
bytes[i*3+1] = someOtherPaletteData[index].green;
bytes[i*3+2] = someOtherPaletteData[index].blue;
}

How to create gray scale QImage(QImage::Format_Indexed) without copying memory

I'm trying to create QImage that wrap a existing image buffer that is created by OpenCv
I was considering use following constructor to do this.
QImage::QImage ( const uchar * data, int width, int height,
int bytesPerLine, Format format )
so, my code is like
QImage qimage((const uchar*)iplImage->imageData,
iplImage->width, iplImage->height,
iplImage->widthStep,
QImage::Format_Indexed); // image buffer not copied!
qimage.setColorTable(grayScaleColorTable); // color table's item count 256 for grayscale.
// now new image buffer is allocated here.
Ok, no memory copy actually was done at the time of calling this ctor.
But, here comes my problem. QImage::setColorTable() is non const member function where QImage allocates new image buffer for copying by its internal detach() function.
I found there was Qt3 support for this kind of problem where ctor could accept color table as argument in its ctor, but I've not found any such support in > Qt4.
How can I create gray scale QImage for existing image buffer?
Thanks for in advance
[EDITED]
Thanks to Stephen Chu, I realized that following contstructors create read/write-able QImage object
QImage ( uchar * data, int width, int height, Format format )
QImage ( uchar * data, int width, int height, int bytesPerLine, Format format )
which even if QImage::setColorTable() is called later right after instantiation, no new buffer is allocated. On the other hand, following constructors receiving 'const'ed data buffer create read-only QImage objects which new buffer is allocated and deep copied from original buffer when any non-const member function like QImage::setColorTable() is called(that I do not want).
QImage ( const uchar * data, int width, int height, Format format )
QImage ( const uchar * data, int width, int height, int bytesPerLine, Format format )

QImage definition

this command line:
QImage:: QImage (uchar * data, int width, int height, int bytesPerLine, Format format)
Would use is it so?
QImage image = new QImage (buffer, 600, 400, jpg)
the bytesPerLine not they mean well, will the photo occupies kb?
thanks
If you do not want to use the bytesPerLine parameter, there is a
QImage::QImage ( uchar * data, int width, int height, Format format )
constructor.
However, Format is not what you might think. Theformatparameter specifies an enum value which decides over the bit depth etc. I.e. enteringjpgor"jpg"there won't work. Check Format-enum for a list of possible values.
I will try to answer the best I can considering the fact that your question is very unclear to me.
From the Qt documentation:
bytesPerLine specifies the number of bytes per line (stride)
Also consider that the format argument, which you specified as jpg, must be given as one of the enum values specified in here.
Best regards
That's how you would use this constructor:
int imageWidth = 800;
int imageHeight = 600;
int bytesPerPixel = 4; // 4 for RGBA, 3 for RGB
int format = QImage::Format_ARGB32; // this is the pixel format - check Qimage::Format enum type for more options
QImage image(yourData, imageWidth, imageHeight, imageWidth * bytesPerPixel, format);
You don't specify the image format (png, jpeg, etc.) but the pixel format (RGB, RGBA, etc.)

how to display image from array of colors data in Qt?

I have a char* data, where every char represents red/green/blue/alpha value of a pixel.
So, the first four numbers are red, green, blue and alpha value of the first pixel, the next four are R, G, B, A value of the pixel on the right and so on.
It represents a picture (with previously known width and height).
Now, I want to somehow take this array and display it on Qt window. How to do it?
I know I should somehow use QPixmap and/or QImage, but I cannot find anything helpful in the documentation.
QImage is designed for access to the various pixels (among other things), so you could do something like this:
QImage DataToQImage( int width, int height, int length, char *data )
{
QImage image( width, height, QImage::Format_ARGB32 );
assert( length % 4 == 0 );
for ( int i = 0; i < length / 4; ++i )
{
int index = i * 4;
QRgb argb = qRgba( data[index + 1], //red
data[index + 2], //green
data[index + 3], //blue
data[index] ); //alpha
image.setPixel( i, argb );
}
return image;
}
Based on coming across another constructor, you might also be able to do this:
QImage DataToQImage( int width, int height, int length, const uchar *data )
{
int bytes_per_line = width * 4;
QImage image( data, width, height, bytes_per_line,
QImage::Format_ARGB32 );
// data is required to be valid throughout the lifetime of the image so
// constructed, and QImages use shared data to make copying quick. I
// don't know how those two features interact, so here I chose to force a
// copy of the image. It could be that the shared data would make a copy
// also, but due to the shared data, we don't really lose anything by
// forcing it.
return image.copy();
}

Resources