Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Send image inside Json through QTcpSocket
Qt 6.11 is out! See what's new in the release blog

Send image inside Json through QTcpSocket

Scheduled Pinned Locked Moved Solved General and Desktop
28 Posts 6 Posters 10.7k Views 3 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • T Offline
    T Offline
    Tamfub
    wrote on last edited by
    #1

    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 QBuffer
    

    For 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 extracts photo_data, this doesn't seem to work:

    QJsonValue photo = obj.take("photo");
    /* photo = QJsonValue(string, "????") */
    

    So, how can I send the QByteArray from server to client properly?

    1 Reply Last reply
    0
    • Christian EhrlicherC Offline
      Christian EhrlicherC Offline
      Christian Ehrlicher
      Lifetime Qt Champion
      wrote on last edited by
      #2

      e.g. by converting the QByteArray to base64 encoding.

      Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
      Visit the Qt Academy at https://academy.qt.io/catalog

      T 1 Reply Last reply
      5
      • Christian EhrlicherC Christian Ehrlicher

        e.g. by converting the QByteArray to base64 encoding.

        T Offline
        T Offline
        Tamfub
        wrote on last edited by
        #3

        @Christian-Ehrlicher
        Hi, i tried:

        qjo.insert("photo", ba.toBase64());
        

        but the IDE says:

        no viable conversion from 'QByteArray' to 'const QJsonValue'
        
        1 Reply Last reply
        0
        • Christian EhrlicherC Offline
          Christian EhrlicherC Offline
          Christian Ehrlicher
          Lifetime Qt Champion
          wrote on last edited by
          #4

          @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.

          Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
          Visit the Qt Academy at https://academy.qt.io/catalog

          T 1 Reply Last reply
          3
          • Christian EhrlicherC Christian Ehrlicher

            @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.

            T Offline
            T Offline
            Tamfub
            wrote on last edited by
            #5

            @Christian-Ehrlicher
            Yes sorry, I meant the compiler. By the way, I tried both

            qjo.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 photo is "\xEF\xBF\xBD\xEF\xBF\xBD\xEF\xBF\xBD\xEF\xBF\xBD" again.

            KroMignonK 1 Reply Last reply
            0
            • T Tamfub

              @Christian-Ehrlicher
              Yes sorry, I meant the compiler. By the way, I tried both

              qjo.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 photo is "\xEF\xBF\xBD\xEF\xBF\xBD\xEF\xBF\xBD\xEF\xBF\xBD" again.

              KroMignonK Offline
              KroMignonK Offline
              KroMignon
              wrote on last edited by
              #6

              @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();  
              
              

              It is an old maxim of mine that when you have excluded the impossible, whatever remains, however improbable, must be the truth. (Sherlock Holmes)

              T 1 Reply Last reply
              2
              • Christian EhrlicherC Offline
                Christian EhrlicherC Offline
                Christian Ehrlicher
                Lifetime Qt Champion
                wrote on last edited by
                #7

                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.

                Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
                Visit the Qt Academy at https://academy.qt.io/catalog

                T 1 Reply Last reply
                3
                • KroMignonK KroMignon

                  @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();  
                  
                  
                  T Offline
                  T Offline
                  Tamfub
                  wrote on last edited by
                  #8

                  @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...
                  
                  KroMignonK 1 Reply Last reply
                  0
                  • T Tamfub

                    @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...
                    
                    KroMignonK Offline
                    KroMignonK Offline
                    KroMignon
                    wrote on last edited by
                    #9

                    @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)

                    It is an old maxim of mine that when you have excluded the impossible, whatever remains, however improbable, must be the truth. (Sherlock Holmes)

                    1 Reply Last reply
                    0
                    • Christian EhrlicherC Christian Ehrlicher

                      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.

                      T Offline
                      T Offline
                      Tamfub
                      wrote on last edited by Tamfub
                      #10

                      @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...
                      
                      1 Reply Last reply
                      0
                      • Christian EhrlicherC Offline
                        Christian EhrlicherC Offline
                        Christian Ehrlicher
                        Lifetime Qt Champion
                        wrote on last edited by
                        #11

                        Because you unpack your json structure wrong I would guess. In the first example you pack it twice as you can see.

                        Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
                        Visit the Qt Academy at https://academy.qt.io/catalog

                        T 1 Reply Last reply
                        1
                        • Christian EhrlicherC Christian Ehrlicher

                          Because you unpack your json structure wrong I would guess. In the first example you pack it twice as you can see.

                          T Offline
                          T Offline
                          Tamfub
                          wrote on last edited by Tamfub
                          #12

                          @Christian-Ehrlicher
                          Ok, I removed the qjo.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?

                          JonBJ 1 Reply Last reply
                          0
                          • Christian EhrlicherC Offline
                            Christian EhrlicherC Offline
                            Christian Ehrlicher
                            Lifetime Qt Champion
                            wrote on last edited by
                            #13

                            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.

                            Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
                            Visit the Qt Academy at https://academy.qt.io/catalog

                            1 Reply Last reply
                            2
                            • T Tamfub

                              @Christian-Ehrlicher
                              Ok, I removed the qjo.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?

                              JonBJ Offline
                              JonBJ Offline
                              JonB
                              wrote on last edited by JonB
                              #14

                              @Tamfub
                              Dunno, let's start with

                              while(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.

                              T 1 Reply Last reply
                              0
                              • JonBJ JonB

                                @Tamfub
                                Dunno, let's start with

                                while(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.

                                T Offline
                                T Offline
                                Tamfub
                                wrote on last edited by
                                #15

                                @Christian-Ehrlicher @JonB
                                Ok, I guess I'll have to revise my protocol, then I'll return to the other problem later :)

                                1 Reply Last reply
                                0
                                • SGaistS Offline
                                  SGaistS Offline
                                  SGaist
                                  Lifetime Qt Champion
                                  wrote on last edited by
                                  #16

                                  Hi,

                                  @Tamfub said in Send image inside Json through QTcpSocket:

                                  QString string = (QString)dataReceived;

                                  dataReceived is a QByteArray, that cast is completely wrong.

                                  Interested in AI ? www.idiap.ch
                                  Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                                  T 1 Reply Last reply
                                  1
                                  • T Offline
                                    T Offline
                                    Tamfub
                                    wrote on last edited by
                                    #17

                                    @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 replaced

                                    out << 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): 
                                    finished
                                    

                                    I guess qDebug() does not print large data?

                                    JonBJ 1 Reply Last reply
                                    0
                                    • T Tamfub

                                      @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 replaced

                                      out << 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): 
                                      finished
                                      

                                      I guess qDebug() does not print large data?

                                      JonBJ Offline
                                      JonBJ Offline
                                      JonB
                                      wrote on last edited by
                                      #18

                                      @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 somewhere qDebug(qPrintable(qString)); or print QString::length().

                                      T 1 Reply Last reply
                                      0
                                      • SGaistS SGaist

                                        Hi,

                                        @Tamfub said in Send image inside Json through QTcpSocket:

                                        QString string = (QString)dataReceived;

                                        dataReceived is a QByteArray, that cast is completely wrong.

                                        T Offline
                                        T Offline
                                        Tamfub
                                        wrote on last edited by
                                        #19

                                        @SGaist
                                        Hi.
                                        Ok, I guess I should use something like QString::fromLatin1(array), right?

                                        1 Reply Last reply
                                        0
                                        • JonBJ JonB

                                          @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 somewhere qDebug(qPrintable(qString)); or print QString::length().

                                          T Offline
                                          T Offline
                                          Tamfub
                                          wrote on last edited by Tamfub
                                          #20

                                          @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(); // 75684
                                          

                                          Client

                                          ds.startTransaction();
                                          QByteArray data;
                                          ds >> data;
                                          
                                          if (!ds.commitTransaction())
                                                  return;
                                          
                                          qDebug() << "data(size): " << risp.size();  // 151368
                                          

                                          How 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();  // 1000000
                                          

                                          instead, the two sizes match!

                                          JonBJ 1 Reply Last reply
                                          0

                                          • Login

                                          • Login or register to search.
                                          • First post
                                            Last post
                                          0
                                          • Categories
                                          • Recent
                                          • Tags
                                          • Popular
                                          • Users
                                          • Groups
                                          • Search
                                          • Get Qt Extensions
                                          • Unsolved