Send image inside Json through QTcpSocket
-
Hello everyone.
I have a local client-server application where data in sent through
QTcpSockets. At a certain point, the client asks for a photo, and the server must send it to the client.Server
Setup:
QByteArray info=""; // Data to be send QJsonObject qjo; QDataStream ds(socket);The server loads the image from the filesystem and fills the related
QByteArray ba:QImage imageObject; imageObject.load(Path/to/image); QPixmap image = QPixmap::fromImage(imageObject); QByteArray ba; // Construct a QByteArray object QBuffer buffer(&ba); // Construct a QBuffer object using the QbyteArray image.save(&buffer, "JPG"); // Save the QImage data into the QBufferFor my application, the server should send not only the image, but also a code meaning that this is the "case" of a photo request:
qjo.insert("request_type", PHOTO); /* PHOTO (=13) is defined in a .h */Now, I would like to do the same thing with
ba:qjo.insert("photo_data", [some way to put ba]); // I can't put ba directly...because the final step is this one:
QJsonDocument doc(qjo); QString strJson(doc.toJson(QJsonDocument::Compact)); info.append(strJson); ds << info;I've tried this:
qjo.insert("photo_data", ba.data()); /* ba.data() = "\xEF\xBF\xBD\xEF\xBF\xBD\xEF\xBF\xBD\xEF\xBF\xBD" */Client
It reads all the data correctly. Then, when it extractsphoto_data, this doesn't seem to work:QJsonValue photo = obj.take("photo"); /* photo = QJsonValue(string, "????") */So, how can I send the
QByteArrayfrom server to client properly? -
e.g. by converting the QByteArray to base64 encoding.
-
e.g. by converting the QByteArray to base64 encoding.
@Christian-Ehrlicher
Hi, i tried:qjo.insert("photo", ba.toBase64());but the IDE says:
no viable conversion from 'QByteArray' to 'const QJsonValue' -
@Tamfub said in Send image inside Json through QTcpSocket:
but the IDE says:
The compiler maybe, but not the IDE...
You have to convert the QByteArray to a QString.
-
@Tamfub said in Send image inside Json through QTcpSocket:
but the IDE says:
The compiler maybe, but not the IDE...
You have to convert the QByteArray to a QString.
@Christian-Ehrlicher
Yes sorry, I meant the compiler. By the way, I tried bothqjo.insert("photo", QString::fromStdString(ba.toBase64().toStdString()));and
qjo.insert("photo", QString::fromUtf8(data));but the result in the client is:
QJsonValue photo = obj.take("photo"); qDebug() << photo.toString(); // Output: "????"And data sent by the server for
photois"\xEF\xBF\xBD\xEF\xBF\xBD\xEF\xBF\xBD\xEF\xBF\xBD"again. -
@Christian-Ehrlicher
Yes sorry, I meant the compiler. By the way, I tried bothqjo.insert("photo", QString::fromStdString(ba.toBase64().toStdString()));and
qjo.insert("photo", QString::fromUtf8(data));but the result in the client is:
QJsonValue photo = obj.take("photo"); qDebug() << photo.toString(); // Output: "????"And data sent by the server for
photois"\xEF\xBF\xBD\xEF\xBF\xBD\xEF\xBF\xBD\xEF\xBF\xBD"again.@Tamfub said in Send image inside Json through QTcpSocket:
qjo.insert("photo", QString::fromStdString(ba.toBase64().toStdString()));
Have you tried this
qjo.insert("photo", QString(ba.toBase64()));?And then:
QJsonValue photo = obj.take("photo"); qDebug() << photo.toString(); -
Then you do something wrong:
QJsonObject obj; obj["photo"] = QString::fromLatin1(QByteArray("\x01\x02").toBase64()); qDebug() << obj["photo"].toString(); // outputs the base64 string 'AQI='QByteArray::toHex() can also be used but is larger.
-
@Tamfub said in Send image inside Json through QTcpSocket:
qjo.insert("photo", QString::fromStdString(ba.toBase64().toStdString()));
Have you tried this
qjo.insert("photo", QString(ba.toBase64()));?And then:
QJsonValue photo = obj.take("photo"); qDebug() << photo.toString();@KroMignon
Yes, I tried and this is the result:Server
qjo.insert("photo", QString(ba.toBase64())); qDebug() << QString(ba.toBase64)); // No output...Client
QJsonValue photo = obj.take("photo"); qDebug() << photo.toString(); // No output... -
@KroMignon
Yes, I tried and this is the result:Server
qjo.insert("photo", QString(ba.toBase64())); qDebug() << QString(ba.toBase64)); // No output...Client
QJsonValue photo = obj.take("photo"); qDebug() << photo.toString(); // No output...@Tamfub said in Send image inside Json through QTcpSocket:
qjo.insert("photo", QString(ba.toBase64()));
Sorry, my fault ==>
qjo.insert("photo", QString::fromLatin1(ba.toBase64()));(as @Christian-Ehrlicher already wrote) -
Then you do something wrong:
QJsonObject obj; obj["photo"] = QString::fromLatin1(QByteArray("\x01\x02").toBase64()); qDebug() << obj["photo"].toString(); // outputs the base64 string 'AQI='QByteArray::toHex() can also be used but is larger.
@Christian-Ehrlicher
I tried these:Server
QJsonObject obj; obj["photo"] = QString::fromLatin1(ba.toBase64()); qjo.insert("photo", obj["photo"].toString()); qDebug() << obj["photo"].toString(); // "AQI="Client
QJsonValue photo = obj.take("photo"); qDebug() << photo.toString(); // "AQI="/********************/
Server
qjo.insert("photo", QString::fromLatin1(ba.toHex())); qDebug() << QString::fromLatin1(ba.toHex()); // No output...Client
QJsonValue photo = obj.take("photo"); qDebug() << photo.toString(); // No output.../********************/
Server
qjo.insert("photo", QString::fromLatin1(ba.toBase64()); qDebug() << QString::fromLatin1(ba.toBase64()); // No output...Client
QJsonValue photo = obj.take("photo"); qDebug() << photo.toString(); // No output... -
Because you unpack your json structure wrong I would guess. In the first example you pack it twice as you can see.
-
Because you unpack your json structure wrong I would guess. In the first example you pack it twice as you can see.
@Christian-Ehrlicher
Ok, I removed theqjo.insert("photo", obj["photo"].toString());line but it still won't work.By the way, I noticed something in my client. This is the part where it receives data from the server:
QByteArray dataReceived; QDataStream ds(sock); while(sock->bytesAvailable()){ ds.startTransaction(); ds >> dataReceived; } ds.commitTransaction(); while(sock->bytesAvailable()){ // Start the transaction ds.startTransaction(); // Read data ds >> dataReceived; // Error checking if ((!ds.commitTransaction()) && (ds.status()!=QDataStream::Ok)){ sock->flush(); qDebug() << "Error!"; return; } } QString string = (QString)dataReceived; QJsonDocument doc = QJsonDocument::fromJson(string.toUtf8()); QJsonObject obj = doc.object(); ... QJsonValue photo = obj.take("photo"); qDebug() << photo.toString();Then the output, in all the examples, is:
Error! Error! Error! Error! Error! Error!and it reaches the part where it reads the photo data. There is something wrong when the client receives data, maybe?
-
Sorry but you should start with one problem first. Properly pack/unpack the data in your json string. Then we can go over to the next problem.
-
@Christian-Ehrlicher
Ok, I removed theqjo.insert("photo", obj["photo"].toString());line but it still won't work.By the way, I noticed something in my client. This is the part where it receives data from the server:
QByteArray dataReceived; QDataStream ds(sock); while(sock->bytesAvailable()){ ds.startTransaction(); ds >> dataReceived; } ds.commitTransaction(); while(sock->bytesAvailable()){ // Start the transaction ds.startTransaction(); // Read data ds >> dataReceived; // Error checking if ((!ds.commitTransaction()) && (ds.status()!=QDataStream::Ok)){ sock->flush(); qDebug() << "Error!"; return; } } QString string = (QString)dataReceived; QJsonDocument doc = QJsonDocument::fromJson(string.toUtf8()); QJsonObject obj = doc.object(); ... QJsonValue photo = obj.take("photo"); qDebug() << photo.toString();Then the output, in all the examples, is:
Error! Error! Error! Error! Error! Error!and it reaches the part where it reads the photo data. There is something wrong when the client receives data, maybe?
@Tamfub
Dunno, let's start withwhile(sock->bytesAvailable()){ ds.startTransaction(); ds >> dataReceived; } ds.commitTransaction();Why would you (at least potentially) start multiple transactions and only commit once at the end?
Next, I don't understand your whole sequential
bytesAvailable()loops. Why two loops? Are you sure your transactions/tests tally against what is being sent in the same fashion?Practice code just sending string
"hello", perhaps with transactions commented out, while you verify the protocol is correct? Then move to the base64 stuff. And debug out the first & last few characters sent & received to verify they correspond before you look at decoding. You want to discover where your issue is little by little. -
@Tamfub
Dunno, let's start withwhile(sock->bytesAvailable()){ ds.startTransaction(); ds >> dataReceived; } ds.commitTransaction();Why would you (at least potentially) start multiple transactions and only commit once at the end?
Next, I don't understand your whole sequential
bytesAvailable()loops. Why two loops? Are you sure your transactions/tests tally against what is being sent in the same fashion?Practice code just sending string
"hello", perhaps with transactions commented out, while you verify the protocol is correct? Then move to the base64 stuff. And debug out the first & last few characters sent & received to verify they correspond before you look at decoding. You want to discover where your issue is little by little. -
Hi,
@Tamfub said in Send image inside Json through QTcpSocket:
QString string = (QString)dataReceived;
dataReceived is a QByteArray, that cast is completely wrong.
-
@Christian-Ehrlicher @JonB
I've given a look to the fortune client and server examples and tried to toy with data.In
server.cpp, I replacedout << fortunes[QRandomGenerator::global()->bounded(fortunes.size())];with
QString str; for(int i=0; i<1000000; i++) str.append("a"); out << str;void Client::readFortune() became:
void Client::readFortune() { in.startTransaction(); QString data; in >> data; qDebug() << "data: " << data; if (!in.commitTransaction()) return; qDebug() << "data (end): "; qDebug() << data; // if (nextFortune == currentFortune) { // QTimer::singleShot(0, this, &Client::requestNewFortune); // return; // } // currentFortune = nextFortune; // //statusLabel->setText(currentFortune); // qDebug() << "current: " << currentFortune; // getFortuneButton->setEnabled(true); qDebug() << "finished"; }The output in the client is:
next: "" next (end): finishedI guess
qDebug()does not print large data? -
@Christian-Ehrlicher @JonB
I've given a look to the fortune client and server examples and tried to toy with data.In
server.cpp, I replacedout << fortunes[QRandomGenerator::global()->bounded(fortunes.size())];with
QString str; for(int i=0; i<1000000; i++) str.append("a"); out << str;void Client::readFortune() became:
void Client::readFortune() { in.startTransaction(); QString data; in >> data; qDebug() << "data: " << data; if (!in.commitTransaction()) return; qDebug() << "data (end): "; qDebug() << data; // if (nextFortune == currentFortune) { // QTimer::singleShot(0, this, &Client::requestNewFortune); // return; // } // currentFortune = nextFortune; // //statusLabel->setText(currentFortune); // qDebug() << "current: " << currentFortune; // getFortuneButton->setEnabled(true); qDebug() << "finished"; }The output in the client is:
next: "" next (end): finishedI guess
qDebug()does not print large data? -
Hi,
@Tamfub said in Send image inside Json through QTcpSocket:
QString string = (QString)dataReceived;
dataReceived is a QByteArray, that cast is completely wrong.
-
@Tamfub said in Send image inside Json through QTcpSocket:
I guess qDebug() does not print large data?
Do not rely on
qDebug()output visibility. I think it says somewhereqDebug(qPrintable(qString)); or printQString::length().@JonB
Ok, I put some printing of the sizes, and found out that receivedData.size() = 2 x sentData.size().Server
ds << QString::fromLatin1(ba.toBase64()); qDebug() << "size: " << QString::fromLatin1(ba.toBase64()).size(); // 75684Client
ds.startTransaction(); QByteArray data; ds >> data; if (!ds.commitTransaction()) return; qDebug() << "data(size): " << risp.size(); // 151368How is this possible? If I try with
QByteArray str; for(int i=0; i<1000000; i++) str.append("a"); ds << str; qDebug() << "size: " << str.size(); // 1000000instead, the two sizes match!