How to load base64 image data from json in QT - c++

I am beginning with QT5 and trying to load an image from base64 json data. I can load directly from a base64 string but is unsuccessful when trying to load from json object.
the error i am getting is
error: conversion from 'QJsonValueRef' to non-scalar type 'QByteArray' requested
I tried changing toUtf8 toAcsii() etc. but similar error are being produced. Any help and suggestions will be much appreciated.
QString strReply = (QString)reply->readAll(); // json data from a servlet (created using gson library)
QJsonDocument jsonResponse = QJsonDocument::fromJson(strReply.toUtf8());
QJsonObject jsonObj = jsonResponse.object();
QByteArray imgbase64 = jsonObj["photo"]; // image data
QImage img;
img.loadFromData(QByteArray::fromBase64(imgbase64));
ui->outputImage->setPixmap(QPixmap::fromImage(img));
ui->outputImage->setScaledContents( true );
ui->outputImage->setSizePolicy( QSizePolicy::Ignored, QSizePolicy::Ignored );

error: conversion from 'QJsonValueRef' to non-scalar type 'QByteArray' requested*
Since you didn't specify this, I'm expect that the error you're seeing is coming from this line: -
QByteArray imgbase64 = jsonObj["photo"]; // image data
Calling the [] operator on a QJsonObject returns a QJsonValue. There is no overloaded = operator in QByteArray to initialise it from a QJsonValue.
What you need to do is use the QJsonValue functions and do something like this: -
QByteArray imgbase64;
if(jsonObj["photo"].isString())
{
imgbase64 = jsonObj["photo"].toString().toUtf8();
}
Since the photo object is expected to be in Base64, it is acceptable as a string object.

Following code converts JSON object image field to QString and QString to QImage -
QString base64img = jsonObj["photo"].toString();
QByteArray by = QByteArray::fromBase64(base64img.toLatin1());
QImage img = QImage::fromData(by,"JPEG");

Related

C++ parse text from .txt file to variables

what is the simplest way to parse data(C++) from my text file and store it to variables?
I have a parse_data.txt with this text:
{"song":"Holiday","artist":"Green Day","Album":"American Idiot","Service":"Spotify"}
I need store Holiday to song variable, Green Day to artist variable...
so QString song = Holiday...
Can someone show me some examples?
Can we assume that you are using QT? If so, there is an response here that can show you an example on how to use here
Here is how you can apply to your code
QString jsonString = [your json string represenation];
QJsonDocument jsonResponse = QJsonDocument::fromJson(jsonString.toUtf8());
QJsonObject jsonObject = jsonResponse.object();
QJsonValue jsonValue = jsonObject["song"];
QString strValue = jsonValue.toString();

QT c++ QSplitter saveState and restoreState

I have a splitter and I want to save his state in file with JSON.
QJsonObject mainJson;
// here I have to convert QByteArray to QString
mainJson.insert("test", QTextCodec::codecForMib(1015)->toUnicode(ui->splitter->saveState()));
QFile file("test.json");
QTextStream textStream;
file.open(QFile::WriteOnly);
textStream.setDevice(&file);
textStream.setCodec("UTF-8");
textStream << QString(QJsonDocument(mainJson).toJson()).toUtf8();
textStream.flush();
file.close();
But file contains this:
\u0000＀\u0000Ā\u0000Ȁ\u0000Ⰱ\u0000쐀\u0000\u0000Ā\u0000Ȁ
Is that ok? And how to convert this back to QByteArray for ui->splitter->restoreState(...);?
PS: I use code from here
The logic in general is to convert the QByteArray to QString, in this case I prefer to convert it to base64 than to use a codec for unicode to avoid the problems of compression and decompression.
Considering the above, the solution is:
Save:
QJsonObject mainJson;
QByteArray state = spliter->saveState();
mainJson.insert("splitter", QJsonValue(QString::fromUtf8(state.toBase64())));
QFile file("settings.json");
if(file.open(QIODevice::WriteOnly)){
file.write(QJsonDocument(mainJson).toJson());
file.close();
}
Restore:
QJsonDocument doc;
QFile file("settings.json");
if(file.open(QIODevice::ReadOnly)){
doc = QJsonDocument::fromJson(file.readAll());
file.close();
}
if(doc.isObject()){
QJsonObject obj = doc.object();
QByteArray state = QByteArray::fromBase64(obj.value("splitter").toString().toUtf8());
spliter->restoreState(state);
}

How to add object to Json file

I am trying to log data from 3 sensors to a json file. All I want to be able to accomplish is to write the Speed, Latitude and Longitude to a Json file, with an object containing each of the above. That is a json file that contains one route object, n sub objects each of which contain speed, latitude, longitude.
These 3 values I get from 3 global QList lists. Below is the json file which is stored locally. (The double values are not actual values, just for testing purposes)
{
"Sensordata": [
{
"Speed": 1,
"GPSLat":-12.5687,
"GPSLong":26.125546
},
{
"Speed": 1,
"GPSLat":-12.5687,
"GPSLong":26.125546
}
]
}
This is what the json must look like and when I add it must be formatted in the same way
void MainWindow::save_to_json() {
QFile file_obj(".../SensorData.json");
if(!file_obj.open(QIODevice::ReadOnly)){
qDebug()<<"Failed to open "<<"SensorData.json";
exit(1);
}
QTextStream file_text(&file_obj);
QString json_string;
json_string = file_text.readAll();
file_obj.close();
QByteArray data_json = json_string.toLocal8Bit();
QJsonDocument doc = QJsonDocument::fromJson(data_json);
QJsonObject rootObj = doc.object();
QJsonValue SensorData = rootObj.value("SensorData");
if(!SensorData.isArray())
{
// array expected - handle error
}
QJsonArray SensorDataArray = SensorData.toArray();
QJsonObject newObject;
newObject["Speed"] = speed_array.takeFirst();
newObject["GPSLat"] = gps_lat.takeFirst();
newObject["GPSLong"] = gps_long.takeFirst();
SensorDataArray.push_back(newObject);
}
ASSERT: "!isEmpty()" in file /home/username/Qt/5.12.1/gcc_64/include /QtCore/qlist.h, line 347
11:32:55: The program has unexpectedly finished.
11:32:55: The process was ended forcefully.
This is the error the above code creates.
To modify the data, given your example, you need to check if the contained data in the QJsonDocument is an array or a simple object. In your case, I suppose you want to append data to an array. Try something like this:
// Read the data
const QString filename = "example.json";
QJsonDocument doc = read(filename);
// Check that it's an array and append new data
QJsonValue sensorData = doc.value("SensorData");
if (!sensorData.isArray()) {
// if the doc is empty you may want to create it
}
// Get the array and insert the data
auto array = sensorData.array();
array.append(QJsonObject{
{"Speed", speed_array.takeFirst()},
{"GPSLat", gps_lat.takeFirst()},
{"GPSLong",gps_long.takeFirst(),
});
// Restore your sensor data
doc.setObject(QJsonObject{{"SensorData", array}});
// Write the new data
write(filename, doc);
A helper functions to read/write JSON documents may avoid the mistake of open/closing a file:
QJsonDocument read(const QString& filename) {
QFile file(filename);
file.open(QIODevice::ReadOnly | QIODevice::Text);
const QString val = file.readAll();
file.close();
return QJsonDocument::fromJson(val.toUtf8());
}
void write(const QString& filename, const QJsonDocument& document) {
QFile file(filename);
file.open(QFile::WriteOnly | QFile::Text | QFile::Truncate);
file.write(document.toJson());
file.close();
}
Updates
To not overwrite the original doc, you must update the field of the root object or use QJsonValueRef.
// Get a reference to your array
QJsonObject root = doc.object();
QJsonValueRef ref = root.find("SensorData").value();
// get the array and insert the data
QJsonArray array = ref.toArray();
array.append(QJsonObject{
{"Speed", speed_array.takeFirst()},
{"GPSLat", gps_lat.takeFirst()},
{"GPSLong",gps_long.takeFirst(),
});
// Update the ref with the new data
ref = array
// update the modified data in the json document
doc.setObject(root);

Qt parsing json using network response binary

Alright, I found something I just don't understand. I am making a request to a web service using QtNetworkManager. For some reason I can't seem to go from the network response to a jsondoc directly, I have to cast it into a string and then BACK into uft8?
void WebAPIengine::handleNetworkData(QNetworkReply *networkReply)
{
//No network error
if (!networkReply->error()){
//Cast to string
QString strReply = (QString)networkReply->readAll();
//This works, jsonDoc will have the json response from webpage
QJsonDocument jsonDoc = QJsonDocument::fromJson(strReply.toUtf8());
//This doesn't work, networkReply->readAll() is said to return a QByteArray.
QJsonDocument jsonDoc2 = QJsonDocument::fromBinaryData(networkReply->readAll());
QJsonObject jsonObj = jsonDoc.object();
data = jsonObj;
}
//Network error
else{
data["Error"] = "WebAPIengine::handleNetworkData()";
}
Now I can not understand why jsonDoc is working and jsonDoc2 is not. Can someone explain?
Once you do a QNetworkReply->readAll(), the QNetworkReply object will be empty. So if you call the QNetworkReply->readAll() method again, you will not get anything.
Moreover I don't understand why you are converting the QByteArray returned by QNetworkReply->readAll() into a QString and then converting it back to QByteArray(by calling QString::toUtf8()) to give it to the QJsonDocument::fromJson function.
You can try doing this:
QByteArray temp = newReply->readAll();
QJsonDocument jsonDoc = QJsonDocument::fromJson(temp); // This should work
Also make sure to know what the content of the JSon document is, i.e. if it is a map (QJsonObject), array(QJSonArray), array of maps or map with an array as value.

Why can't I parse the Cryptsy JSON API with Qt5/C++?

I'm trying to parse this JSON Web-API using Qt5 and C++ using QJsonDocument and QJsonObject as seen here. But I fail to access the JSON value of the QJsonObject.
This is what I've tried so far:
// Contains the whole API as QString...
QString data = QString(reply->readAll());
// Reads the JSON as QJsonDocument...
QJsonDocument jsonResponse = QJsonDocument::fromJson(data.toUtf8());
// Reads the JSON as QJsonObject...
QJsonObject jsonObject = jsonResponse.object();
Now I have my object well prepared, but trying to access the values of the JSON somehow fails:
// This returns an empty string ""!?!
qDebug() << jsonObject.value("success").toString();
Well, maybe I got the keys wrong:
// Let's check the keys...
QStringList stringList = jsonObject.keys();
for (QStringList::Iterator it = stringList.begin(); it != stringList.end(); ++it)
{
// This returns "success" and "return" - huh!?!
qDebug() << *it;
}
OK, the keys are veryfied, why is it not working?
// Let's check the values by using the keys directly...
for (QStringList::Iterator it = stringList.begin(); it != stringList.end(); ++it)
{
// This returns empty strings "" and "" - now what?!?
qDebug() << jsonObject.value(*it).toString();
}
This again, makes no sense at all. I can't see why I can not access the value of the JSON object by the keys. Any idea?
I tried exactly the same code on other JSON APIs (for example this one) without any issues. I am totally stuck here.
Here's my solution for Qt5 Json parsing the Cryptsy API.
QEventLoop loopEvent;
QNetworkAccessManager namMNGR;
QObject::connect(&namMNGR, SIGNAL(finished(QNetworkReply*)), &loopEvent, SLOT(quit()));
QNetworkRequest req(QUrl(QString("http://pubapi.cryptsy.com/api.php?method=singlemarketdata&marketid=%1").arg(marketID)));
QNetworkReply *reply = namMNGR.get(req);
loopEvent.exec();
//Json API parsing begins.
QString jsonSTR = reply->readAll();
if (!(reply->error() == QNetworkReply::NoError)) {
delete reply; //API Connection Problem.
}
QJsonDocument jsonDocument = QJsonDocument::fromJson(jsonSTR.toUtf8());
QJsonObject obj1 = jsonDocument.object();
QJsonValue val1 = obj1.value(obj1.keys().first());
QJsonObject obj2 = val1.toObject();
QJsonValue val2 = obj2.value(obj2.keys().first());
QJsonObject obj3 = val2.toObject();
QJsonValue marketDataValue = obj3.value(obj3.keys().first());
QJsonObject marketDataObject = marketDataValue.toObject();
QJsonArray sellordersArray = marketDataObject["sellorders"].toArray();
Have you managed to get Authenticated POST API data from Qt5? I'm trying to figure out how to do it.