Save QImage from BYTE buffer segfaults ?
-
Hi, I have a BYTE buffer that gets populated with data representing an image. I want to save that data as a .BMP image file on disk:
BYTE *buf = new BYTE(imWidth * imHeight); //Populate buf with data using API call here (not shown) QImage img(buf, imWidth, imHeight, QImage::Format_Grayscale8); img.save("image.bmp", "BMP"); delete [] buf;
It works absolutely fine sometimes. Other times it crashes when saving the image and generates an empty .bmp file.
I can't understand why it sometimes works and other times it doesn't ?
-
try:
BYTE *buf = new BYTE[imWidth * imHeight];
-
Hi,
Are you sure you are putting valid data in there before making a QImage out of it ?
Are you sure the buffer stays valid until the file is written ?
-
FWIW, you cannot make the absolute assumption that buf will be 32bit word aligned. If I had to guess, that would be my guess as to why it crashes sometimes. The Qt docs ae specific about the need for buf to be 32bit word aligned.
-
@SGaist said in Save QImage from BYTE buffer segfaults ?:
Hi,
Are you sure you are putting valid data in there before making a QImage out of it ?
Are you sure the buffer stays valid until the file is written ?I'm pretty sure that the buffer stays valid.
The data is always written to the buffer the same way, but I guess it could be invalid. How would I check that after the buffer has been populated ?
-
@Kent-Dorfman said in Save QImage from BYTE buffer segfaults ?:
FWIW, you cannot make the absolute assumption that buf will be 32bit word aligned. If I had to guess, that would be my guess as to why it crashes sometimes. The Qt docs ae specific about the need for buf to be 32bit word aligned.
Yes I saw that in the documentation. I assumed that if buffer is being populated the same way each time and that if it works sometimes, then it should be fine.
Does Qt have any other way to get around this besides using another image processing library to save the image ?
-
What are you using to fill that buffer ?
Where do these data come from ?
-
@SGaist said in Save QImage from BYTE buffer segfaults ?:
What are you using to fill that buffer ?
Where do these data come from ?It's populated using an API call which finishes successfully. So I can only interrogate the validity of the data after its completed.
-
That's a bit short on details. An API call can be a method from a library your are using or a remote call to a REST service.
What kind of image are you getting ?
-
@R-P-H said in Save QImage from BYTE buffer segfaults ?:
I assumed that if buffer is being populated the same way each time and that if it works sometimes, then it should be fine.
Even if it does it would depend on your image size (or better: bytes per line). If it's a multiple of 4 it does not crash, if it's something else the alignment is wrong.
-
@SGaist said in Save QImage from BYTE buffer segfaults ?:
That's a bit short on details. An API call can be a method from a library your are using or a remote call to a REST service.
What kind of image are you getting ?
It's from a library. The API reference is very short on details. It's a 256 gray-level image.
-
@Christian-Ehrlicher said in Save QImage from BYTE buffer segfaults ?:
@R-P-H said in Save QImage from BYTE buffer segfaults ?:
I assumed that if buffer is being populated the same way each time and that if it works sometimes, then it should be fine.
Even if it does it would depend on your image size (or better: bytes per line). If it's a multiple of 4 it does not crash, if it's something else the alignment is wrong.
The image size is always the same (260 x 300 px).
-
And one byte per pixel ?
-
@SGaist said in Save QImage from BYTE buffer segfaults ?:
And one byte per pixel ?
That is correct yes.
-
Can you get the stack trace of the crash ?
-
@SGaist said in Save QImage from BYTE buffer segfaults ?:
Can you get the stack trace of the crash ?
I'm testing the application on another machine using the executable. I don't think I'd be able to get it without QT or another IDE right ?
-
Windows machine ?
-
@SGaist said in Save QImage from BYTE buffer segfaults ?:
Windows machine ?
Yes it is. Windows 7 and also Windows 10.
-
try:
BYTE *buf = new BYTE[imWidth * imHeight];
-
@mranger90 said in Save QImage from BYTE buffer segfaults ?:
try:
BYTE *buf = new BYTE[imWidth * imHeight];Hi, it is not crashing anymore, however the image seems to be coming out completely black. I will confirm tomorrow if the image is supposed to be completely black or not...
-
From the documentation
https://doc.qt.io/qt-5/qimage.html#QImage-4
data must be32-bit aligned
, and each scanline of data in the image must also be32-bit aligned
.So (as far as I understand) that is not enough to have memory buffer aligned to 32 bit address, also each line have to be aligned to 32 bit address. So if you have image that is 260x300 pixels, a whole line will take 288 bytes. So for whole image you should have 288*300 bytes which is more than you have provided.
-
@Jarek-B said in Save QImage from BYTE buffer segfaults ?:
From the documentation
https://doc.qt.io/qt-5/qimage.html#QImage-4
data must be32-bit aligned
, and each scanline of data in the image must also be32-bit aligned
.So (as far as I understand) that is not enough to have memory buffer aligned to 32 bit address, also each line have to be aligned to 32 bit address. So if you have image that is 260x300 pixels, a whole line will take 288 bytes. So for whole image you should have 288*300 bytes which is more than you have provided.
Hi, interesting...I have not seen any examples like that. How are you arriving at 288 bytes ? Are you suggesting I make the buffer 288x300 bytes instead ?
-
@R-P-H Of course it's black, the data never gets initialized.
Also, the reason why it doesn't crash is because:
BYTE *buf = new BYTE(x * y); // allocates a single byte, initialized to the value of (x * y)
BYTE *buf = new BYTE[x * y]; // allocates an array of bytes whose size is x * y
-
@mranger90 said in Save QImage from BYTE buffer segfaults ?:
@R-P-H Of course it's black, the data never gets initialized.
Also, the reason why it doesn't crash is because:
BYTE *buf = new BYTE(x * y); // allocates a single byte, initialized to the value of (x * y)
BYTE *buf = new BYTE[x * y]; // allocates an array of bytes whose size is x * yI don't quite understand what you're saying to be honest. Where are you saying the issue is ?
-
@R-P-H here is the amended code
// allocates a buffer of imWidth * imHeight bytes, which depending on the compiler // settings will either be initialized to zero, or may contain garbage BYTE *buf = new BYTE[imWidth * imHeight]; // creates a QImage based on the data in the buffer, QImage img(buf, imWidth, imHeight, QImage::Format_Grayscale8); // saves the data img.save("image.bmp", "BMP"); delete [] buf;
The point is that you never put actual image data into the buffer.
-
@mranger90 said in Save QImage from BYTE buffer segfaults ?:
@R-P-H here is the amended code
// allocates a buffer of imWidth * imHeight bytes, which depending on the compiler // settings will either be initialized to zero, or may contain garbage BYTE *buf = new BYTE[imWidth * imHeight]; // creates a QImage based on the data in the buffer, QImage img(buf, imWidth, imHeight, QImage::Format_Grayscale8); // saves the data img.save("image.bmp", "BMP"); delete [] buf;
The point is that you never put actual image data into the buffer.
This is already what I did according to your first post. The buffer IS populated, I just didn't show that API call. I will modify my original post to make this clear...
So the result is a completely black image. This may be normal but I will have to check with the API provider.
EDIT: I have edited my original post.
-
Is that some private library you can't share ? Or would it be possible to have more information about that API ?
-
@SGaist said in Save QImage from BYTE buffer segfaults ?:
Is that some private library you can't share ? Or would it be possible to have more information about that API ?
Your assumption is correct. There really aren't any additional details on using this API function. It simply takes as input a reference to the buffer and a unique id of the capturing device. It then populates the buffer in place. The example in the documentation initializes the buffer the same way as shown in my original post.
If we are sure the error is on the API side, then they will need to fix that.
I made the assumption that the error was in saving the image to disk.
-
Then are you sure their BYTE type is not something custom ? Do they also show how to access the data ?
Is it the Windows BYTE type ?
-
-
@Jarek-B said in Save QImage from BYTE buffer segfaults ?:
Just round up space that you need for one line
280 / 32 = 8.75
9 * 32 = 288I tried:
BYTE *buf = new BYTE(288 * 300);
Result is exactly the same. Still crashes on occasion.
-
@SGaist said in Save QImage from BYTE buffer segfaults ?:
Then are you sure their BYTE type is not something custom ? Do they also show how to access the data ?
Is it the Windows BYTE type ?
They do not show how to access the data afterwards.
It's defined as
typedef unsigned char BYTE;
fromwindows.h
.
-
@mranger90 said in Save QImage from BYTE buffer segfaults ?:
@R-P-H Of course it's black, the data never gets initialized.
Also, the reason why it doesn't crash is because:
BYTE *buf = new BYTE(x * y); // allocates a single byte, initialized to the value of (x * y)
BYTE *buf = new BYTE[x * y]; // allocates an array of bytes whose size is x * yThe image is always black and it's not supposed to be, so this doesn't work.
-
Hi, you could try explicitly specify the number of bytes per line:
Edit: also, it could be that your deleting the buffer before the QImage is deleted:BYTE *buf = new BYTE(imWidth * imHeight); //Populate buf with data using API call here (not shown) { QImage img(buf, imWidth, imHeight, imWidth, QImage::Format_Grayscale8); img.save("image.bmp", "BMP"); } delete [] buf;
-
@hskoglund said in Save QImage from BYTE buffer segfaults ?:
Hi, you could try explicitly specify the number of bytes per line:
Edit: also, it could be that your deleting the buffer before the QImage is deleted:BYTE *buf = new BYTE(imWidth * imHeight); //Populate buf with data using API call here (not shown) { QImage img(buf, imWidth, imHeight, imWidth, QImage::Format_Grayscale8); img.save("image.bmp", "BMP"); } delete [] buf;
Hi, thanks for the suggestion. I tried it and result is the same...still crashes on occasion.
I also tried with removing the
delete [] buf
line and still the same.
-
@R-P-H
If yourBYTE
meansunsigned char
, then the expression ofnew BYTE(imWidth * imHeight)
is definitely wrong.
As @mranger90 says, that really means you allocate a buf of only one byte size, whose value is (imWidth * imHeight).
So I won't be surprised that it crashes.
-
@Bonnie said in Save QImage from BYTE buffer segfaults ?:
@R-P-H
If yourBYTE
meansunsigned char
, then the expression ofnew BYTE(imWidth * imHeight)
is definitely wrong.
As @mranger90 says, that really means you allocate a buf of only one byte size, whose value is (imWidth * imHeight).
So I won't be surprised that it crashes.I tried with
new BYTE[imWidth * imHeight]
as well but the image is always black.
-
@R-P-H
Right, this is another problem.
How can you be sure your populated data is not all black?
I will suggest you do some tests without Qt classes.BYTE *buf = new BYTE[imWidth * imHeight]; //Populate buf with data using API call here (not shown) bool AllZero = true; for(int i = 0; i < imWidth * imHeight; i++) { if(buf[i] != 0) AllZero = false; } qDebug() << "AllZero :" << AllZero; delete [] buf;
Or you can just print all of the data to see whether it is all zero(black).
-
@Bonnie said in Save QImage from BYTE buffer segfaults ?:
@R-P-H
Right, this is another problem.
How can you be sure your populated data is not all black?
I will suggest you do some tests without Qt classes.BYTE *buf = new BYTE[imWidth * imHeight]; //Populate buf with data using API call here (not shown) bool AllZero = true; for(int i = 0; i < imWidth * imHeight; i++) { if(buf[i] != 0) AllZero = false; } qDebug() << "AllZero :" << AllZero; delete [] buf;
Or you can just print all of the data to see whether it is all zero(black).
Yes it's all black everytime.
-
I would like to try save the buffer to a
BMP image using only standard C++ just to check that it's not a problem with using QImage. But I haven't been able to get that working yet...
-
QImage is quite reliable, for example if I add just 2 for loops to change the pixels to something not black:
int imWidth = 260; int imHeight = 300; typedef unsigned char BYTE; BYTE *buf = new BYTE[imWidth * imHeight]; for (int y = 0; (y < imHeight); ++y) for (int x = 0; (x < imWidth); ++x) buf[x + y * imWidth] = x*x + y*y; QImage img(buf, imWidth, imHeight, QImage::Format_Grayscale8); img.save("image.bmp", "BMP"); delete [] buf;
I get: