Receiving jpeg through socket and yet unable to display on Qt - c++

I trying to send and receive jpeg images (image size around: 1kb) from my client socket. I have successfully send and receive the image data by checking the size of the data. However when I tried to past the image data to QByteArray and display on QImage, nothing was shown. The code below is a snippet of the receiving and displaying jpeg image.
Server.cpp
memcpy(&Rbuffer, ptr, msgCtl.iMsgLen - 8);
ptr += msgCtl.iMsgLen - 8;
cout << "Size of the image data recieve from the send buffer is " << sizeof(Rbuffer) << endl;
QByteArray ba = QByteArray::fromRawData(Rbuffer, sizeof(Rbuffer));
QBuffer qbuff(&ba);
qbuff.open(QIODevice::ReadOnly);
//QImageReader qimg ("C:\\test.jpg");
QImageReader qimg (&qbuff,"JPG");
qimg.setDecideFormatFromContent(true);
qimg.setDevice(&qbuff);
QImage img = qimg.read();
if (!img.isNull()){
cout << "no problem" << endl;
}
imageView->setPixmap(QPixmap::fromImage(img));
Hope someone could guide me on this. Thank you

On Windows, you have to copy the imageformats directory to your build directory.
eg.
C:\Qt\5.7\msvc2015_64\plugins\imageformats to my_build_dir\imageformats

Try this code:
QPixmap scaledPixmap = QPixmap::fromImage(image).scaled(
QSize(imageWidth, imageHeight),
Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
imageView->setScaledContents(false);
imageView->setPixmap(scaledPixmap);

Related

how to transfer QImage from QLocalServer to QLocalSocket

I have two mac apps that communicate with each other using QLocalSocket.
Able to send the received QString but not able to send the received QImage Below is my code.
SERVER SIDE CODE
QImage image(":/asset/logo_active.png");
QByteArray ba;
qDebug() << image.sizeInBytes() <<image.size();
ba.append((char *)image.bits(),image.sizeInBytes());
qDebug() <<ba.size(); //262144
this->mSocket->write(ba);
if(!this->mSocket->waitForBytesWritten(-1))
{
qDebug() << "writen Bytes error " << this->mSocket->errorString();
}
this->mSocket->flush();
CLIENT SIDE CODE
connect(mLocalSocket,&QLocalSocket::readyRead, [&]() {
QByteArray ba;
ba = mLocalSocket->readAll();
qDebug() << "size is" << ba.size(); // size is 0
QImage image((uchar *)ba.data(),1024,768,QImage::Format_RGB32);
ui->labelStream->setPixmap(QPixmap::fromImage(img));
});
at sender 262144 is the byte-array size
but at the receiver, byte-array size is 0
Do let me know if I am missing anything.
Thanks In Advance
Finally I got the solutions I used QDataStream below is the code example.
SERVER SIDE CODE:
QDataStream T(mSocket);
T.setVersion(QDataStream::Qt_5_7);
QByteArray ba;
ba.append((char *)img.bits(),img.sizeInBytes());
T << ba;
mSocket->flush();
CLIENT SIDE CODE
QByteArray jsonData;
QDataStream socketStream(mLocalSocket);
socketStream.setVersion(QDataStream::Qt_5_7);
for (;;) {
socketStream.startTransaction();
socketStream >> jsonData;
if (socketStream.commitTransaction()) {
QImage image((uchar *)jsonData.data(),640,480,QImage::Format_RGB888);
ui->labelStream->setPixmap(QPixmap::fromImage(image));
}else {
// the read failed, the socket goes automatically back to the state it was in before the transaction started
// we just exit the loop and wait for more data to become available
break;
}
}
Thanks, Everyone for your support also Stackoverflow.

C++ Windows RPC how to define the MIDL can transmit null terminated char array

My project is use C++ Windows RPC to upload image(512*512) from client to server. I do not use WIN RPC before, So I tried some examples include send basic "Hello world" Message to server, but the huge issue is the function can't send unsigned char* include '\0'. I mean there are a lot of '\0' characters in the char array, they can't send to the server.
I think it is because I defined wrong MIDL function.
I tried:
void Output(
[in, out, size_is(1048576), string] unsigned char* szString);
another one
void Output1(
[in, length_is(1048576)] unsigned char[]);
But both can't work.
I use opencv3.2 to read image to Mat structure, and it can get Mat data and use memcpy to copy the Mat.data then create a new image in local client. But when I send Mat.data to server, the first of characters in the Mat.data is '\0'. All the Mat.data can't send to server.
My Client core code(It has include all require header) is
Mat I = imread("U:\\normal.jpg", IMREAD_ANYDEPTH);
if (I.empty())
{
std::cout << "!!! Failed imread(): image not found" << std::endl;
// don't let the execution continue, else imshow() will crash.
}
if (!I.data) {
std::cout << "can't open or find image" << std::endl;
//return -1;
}
I.convertTo(I, CV_32F);
I = (I.reshape(0, 1)); // to make it continuous
char tr[512*512*4];
memcpy_s(tr, 512 * 512 * 4, I.data, 512*512 * 4);
//snprintf(tr, 512*512*4,"%s", I.data);
Mat out = Mat(512,512, CV_32F, &tr[0]);
namedWindow("Display window", CV_WINDOW_AUTOSIZE);// Create a window for display.
imshow("Display window", out);
waitKey(5000);
...
RpcTryExcept
{
std::clog << "Calling Open" << std::endl;
output((unsigned char* )tr); // process the function, send data to server
//output1((unsigned char* )tr);
}

QT failed to load Image from Buffer

My work Environment : Qt 5.8 MSVC2015 64bit, QT GraphicsView, Windows 7 64 bit
I am loading image from buffer (a demon process is going send a image buffer), but it failed to create image with buffer.
QFile file("D:\\2.png");
if (!file.open(QFile::ReadOnly))
qDebug() << "Error failed to Open file";
QByteArray array = file.readAll();
array = array.toBase64();
QImage tempimage((uchar *)array.data(), 250, 250, QImage::Format_RGBX8888);
if (!tempimage.isNull()) {
///I always get this error
qDebug() << "Error!!! failed to create a image!";
}
Any idea what I am missing here ?
Why are you converting to base64?
Wait, where are you converting from PNG to an image plane?
Try bool QImage::loadFromData(const QByteArray &data, const char *format = Q_NULLPTR) to load the PNG instead of the CTor with the raw data.
If your wire format isn't PNG (and is in fact base64 encoded raw pixel data) then you want to convert FROM base64.
Thanks for all suggestion & help.
I fix my mistakes removed base64 conversion & loaded buffer using loadFromData with QByteArray reinterpret_cast:
Here is a final solution :
QFile file("D:\\2.png");
if (!file.open(QFile::ReadOnly))
qDebug() << "Error failed to Open file";
QByteArray array = file.readAll();
QImage tempimage;
//// This very important to cast in below format, QByteArray don't work as arguments.
tempimage.loadFromData(reinterpret_cast<const uchar *>(array.data()),array.size());
if (tempimage.isNull()) {
qDebug() << "Error!!! failed to create a image!";
}

How to read my application screen pixel data with Qt

I am trying to read my application screen pixel data in my Qt Qml application.
The first approach was grabToImage(), which is fast in my PC. But the same is taking seconds to grab image in my embedded device.
So I tried to read /dev/fb0, using QFile::readAll,
QFile file("/dev/fb0");
QFile dataFile("/home/icu/WorkSpace/Samples/FBRead/Exe/data.bin");
if(!file.open(QIODevice::ReadOnly))
{
qDebug() << Q_FUNC_INFO << file.errorString();
}
if(!dataFile.open(QIODevice::WriteOnly))
{
qDebug() << Q_FUNC_INFO << dataFile.errorString();
}
QTextStream in(&file);
QString data;
qDebug() << Q_FUNC_INFO << "start read";
// while(!in.atEnd())
// {
qDebug() << Q_FUNC_INFO << "read";
data = in.readAll();
// qDebug() << Q_FUNC_INFO << data;
// }
QByteArray dataBytes;
dataBytes.append(data);
dataFile.write(dataBytes);
file.close();
dataFile.close();
I tried to open the file with some tool which shows image reading from raw file. But it did not show any data. When I open the file data is like 01 01 01 00 01 01 01 00 ...
Is there any alternate way to read my screen pixel data fast? Thanks
I'm not sure if using a QTextStream and converting data to QString and then back to QByteArray is the best way to do it. As explained in Qt's documentation constructing a QString from QByteArray forces a conversion to UTF-8 and also stops copying at the first null character, so you are modifying your pixel data and not getting it completely. Try copying data directly between files instead:
bool grabScreenToFile(const QString& outPath) {
QFile inFile("/dev/fb0");
QFile outFile(outPath);
// ...
outFile.write(inFile.readAll());
return true;
}
To check if this is copying the actual content of the file and you have no problem with it (truncation, conversions, ...), compare with the file obtained using cat /dev/fb0 > grab.raw (note that it is not a JPEG or PNG image but a raw buffer).
/dev/fb0
This link contains a long explanation about grabbing the framebuffer from the /dev/fb0 device. Basically, it points out that you must pay attention to the depth of the buffer, since pixels may be packed in different ways.
On the other hand, have you tried any other of the grabbing methods provided by Qt, such as QScreen::grabWindow? Maybe its performance is better that the QML's QQuickItem::grabToImage (which is the one I guess you are using). Indeed, the documentation states:
This function will render the item to an offscreen surface and copy that surface from the GPU's memory into the CPU's memory, which can be quite costly.
Following code is a modification of the screenshot example.
auto screen = QGuiApplication::primaryScreen();
if (const QWindow *window = windowHandle()) {
screen = window->screen();
}
if (screen) {
const auto pixmap = screen->grabWindow(yourWidget->winId());
// ...
}

Retrieving video size using QtGStreamer returns ZERO

I'm playing with QtGStreamer 0.10.0 and I'm trying to retrieve the video size but it's returning ZERO for height and width values.
However, I am able to play the video with no problems on a QImage.
QGst::init();
pipeline = QGst::Pipeline::create();
filesrc = QGst::ElementFactory::make("filesrc");
filesrc->setProperty("location", "sample.avi");
pipeline->add(filesrc);
decodebin = QGst::ElementFactory::make("decodebin2").dynamicCast<QGst::Bin>();
pipeline->add(decodebin);
QGlib::connect(decodebin, "pad-added", this, &MyMultimedia::onNewDecodedPad);
QGlib::connect(decodebin, "pad-removed", this, &MyMultimedia::onRemoveDecodedPad);
filesrc->link(decodebin);
// more code ...
The code above shows the begining of the pipeline setup. By connecting my method MyMultimedia::onNewDecodedPad on the signal "pad-added" I have access to the data of the video. At least that's what I think.
void MyMultimedia::onNewDecodedPad(QGst::PadPtr pad)
{
QGst::CapsPtr caps = pad->caps();
QGst::StructurePtr structure = caps->internalStructure(0);
if (structure->name().contains("video/x-raw"))
{
// Trying to print width and height using a couple of different ways,
// but all of them returns 0 for width/height.
qDebug() << "#1 Size: " << structure->value("width").get<int>() << "x" << structure->value("height").get<int>();
qDebug() << "#2 Size: " << structure->value("width").toInt() << "x" << structure->value("height").toInt();
qDebug() << "#3 Size: " << structure.data()->value("width").get<int>() << "x" << structure.data()->value("height").get<int>();
// numberOfFields also returns 0, which is very wierd.
qDebug() << "numberOfFields:" << structure->numberOfFields();
}
// some other code
}
I wonder what I might be doing wrong. Any tips? I was unable to find a relevant example on the web using this API.
Solved it. At onNewDecodedPad() you still don't have access to information about the video frames.
The class MyMultimedia inherits from QGst::Utils::ApplicationSink, so I had to implement a method named QGst::FlowReturn MyMultimedia::newBuffer() that is called by QtGstreamer whenever a new frame is ready.
In other words, use this method to copy the frame of the video to a QImage. What I didn't know is that pullBuffer() returns a QGst::BufferPtr, which has a QGst::CapsPtr. It's an internal structure from this var that holds the information I was looking for:
QGst::FlowReturn MyMultimedia::newBuffer()
{
QGst::BufferPtr buf_ptr = pullBuffer();
QGst::CapsPtr caps_ptr = buf_ptr->caps();
QGst::StructurePtr struct_ptr = caps_ptr->internalStructure(0);
qDebug() << struct_ptr->value("width").get<int>() <<
"x" <<
struct_ptr->value("height").get<int>();
// ...
}