Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to store a QPixmap in JSON, via QByteArray?

I have a QByteArray, which I want to save in a JSON file using Qt and also be able to read from it again. Since JSON natively can't store raw data, I think the best way would probably be a string? The goal is to save a QPixmap this way:

{
  "format" : "jpg",
  "data" : "...jibberish..."
}

How do I achieve this and how do I read from this JSON Object again (I am using Qt5)? What I have right now looks this way:

QPixmap p;
...

QByteArray ba;
QBuffer buffer(&ba);

buffer.open(QIODevice::WriteOnly);
p.save(&buffer, "jpg");

QJsonObject json;
gameObject["data"] = QString(buffer.data());

QJsonDocument doc(json);
file.write(doc.toJson());

But the resulting 'jibberish' is way to short to contain the whole image.

like image 794
fuji Avatar asked Sep 03 '15 12:09

fuji


1 Answers

A QString cannot be constructed from an arbitrary QByteArray. You need to encode the byte array such that it is convertible to a string first. It is somewhat misleading that a QString is constructible from a QByteArray from the C++ semantics point of view. Whether it is really constructible depends on what's in the QByteArray.

QByteArray::toBase64 and fromBase64 are one way of doing it.

Since you would want to save the pixmap without losing its contents, you should not save it in a lossy format like JPG. Use PNG instead. Only use JPG if you're not repeatedly loading and storing the same pixmap while doing the full json->pixmap->json circuit.

There's another gotcha: for a pixmap to store or load itself, it needs to internally convert to/from QImage. This involves potentially color format conversions. Such conversions may lose data. You have to be careful to ensure that any roundtrips are made with the same format.

Ideally, you should be using QImage instead of a QPixmap. In modern Qt, a QPixmap is just a thin wrapper around a QImage anyway.

// https://github.com/KubaO/stackoverflown/tree/master/questions/pixmap-to-json-32376119
#include <QtGui>

QJsonValue jsonValFromPixmap(const QPixmap &p) {
  QBuffer buffer;
  buffer.open(QIODevice::WriteOnly);
  p.save(&buffer, "PNG");
  auto const encoded = buffer.data().toBase64();
  return {QLatin1String(encoded)};
}

QPixmap pixmapFrom(const QJsonValue &val) {
  auto const encoded = val.toString().toLatin1();
  QPixmap p;
  p.loadFromData(QByteArray::fromBase64(encoded), "PNG");
  return p;
}

int main(int argc, char **argv) {
   QGuiApplication app{argc, argv};
   QImage img{32, 32, QImage::Format_RGB32};
   img.fill(Qt::red);
   auto pix = QPixmap::fromImage(img);
   auto val = jsonValFromPixmap(pix);
   auto pix2 = pixmapFrom(val);
   auto img2 = pix2.toImage();
   Q_ASSERT(img == img2);
}
like image 192
Kuba hasn't forgotten Monica Avatar answered Nov 20 '22 03:11

Kuba hasn't forgotten Monica