I am building two apps, one client, and one server. I need to send and image via RPC to the server app and convert it back into QImage.
When I do the conversion, I noticed that the images don't match and I need them to match 100%.
Here's what I tried:
[Client]
void ServerConnection::MakeRequest(QImage& imageData, const uint8_t imageId) {
// Reset each time received images
receivedImages_.clear();
// Remove the limits on sizes
grpc::ChannelArguments ch_args;
ch_args.SetMaxReceiveMessageSize(-1);
ch_args.SetMaxSendMessageSize(-1);
channel_ = grpc::CreateCustomChannel(ip_ + ":" + std::to_string(port_), grpc::InsecureChannelCredentials(), ch_args);
// Create a stub to manage the connection
stub_ = ImageService::NewStub(channel_);
// Create a request message
ImageRequest request;
request.set_image_id(std::to_string(imageId));
// Convert QImage to QByteArray with JPG format
QByteArray byteArray;
QBuffer buffer(&byteArray);
buffer.open(QIODevice::WriteOnly);
if (!imageData.isNull() && imageData.save(&buffer, "JPG")) {
// Set the image data in the request
request.set_image_data(byteArray.toBase64().toStdString());
// Create a response message
ImageResponse response;
// Create a new context for this RPC
grpc::ClientContext context;
// Call the RPC method
grpc::Status status = stub_->ProcessImage(&context, request, &response);
// Handle the response
if (status.ok()) {
// Handle response
std::cout << "Received set ID: " << response.set_id() << std::endl;
for (const auto& image_data : response.image_data()) {
// Convert QByteArray to QImage
QByteArray byteArray = QByteArray::fromBase64(QString::fromStdString(image_data).toUtf8());
QImage image = QImage::fromData(byteArray, "JPG");
receivedImages_.push_back(image);
}
} else {
// Handle error
std::cerr << "Error: " << status.error_message() << std::endl;
}
} else {
// Handle error saving QImage
std::cerr << "Error: Failed to save QImage to QByteArray" << std::endl;
}
}
[Server]
grpc::Status ProcessImage(grpc::ServerContext* context, const ImageRequest* request, ImageResponse* response) override {
QByteArray imageData = QByteArray::fromBase64(request->image_data().c_str());
// Check if image data is valid
if (imageData.isNull()) {
return grpc::Status::CANCELLED;
} else {
std::cout << "Image data is valid" << std::endl;
}
// Convert QImage to cv::Mat
QImage image;
image.loadFromData(reinterpret_cast<const uchar*>(imageData.constData()), imageData.size());
QImage image;
// Save QImage
QString savePath = "output_image.jpg";
image.save(savePath, "JPG");
// ..........
return grpc::Status::OK;
}
I tried to compare data after conversion on the client, and on the server when it's received and they match. So, I'm stuck with how to properly convert images.
How to correctly convert image to QByteArray and vice versa?
Maybe you already are doing it right? How would you know? :)
Get rid of grpc as it's not necessary to just demonstrate the problem. Start with the basics and go from there:
Load QImage from a file, save the same QImage to a differenet file, compare the files with whatever tool you're using. Once that works,
Load QImage from a file, dump into a QByteArray, make a new QImage from that, save to a file, compare. Then
Load QImage from a file, into a QByteArray, into a Base-64 encoded string, back into a QByteArray, into a QImage, save to a file, compare. Then
Load QImage into a file,...,into Base-64-encoded string, then transfer it in-process via grpc, then reverse to a QImage, save to file, compare. Then
Same as #4, but separate the grpc endpoints across two processes running on the same machine.
If you do it that way, you'll have a clear indication of where the problem occurs.
Of course, the image comparison can be done using Qt itself. To get you started, here's how to do steps 1..4, but painting the image instead of loading it from an external file:
#include <QtGui>
#include <QDebug>
int main(int, char*[])
{
// Source
QImage src({64, 64}, QImage::Format_RGB32);
QPainter(&src).fillRect(src.rect(), Qt::red);
QBuffer srcBuf;
srcBuf.open(QBuffer::ReadWrite);
src.save(&srcBuf, "PNG");
srcBuf.close();
QByteArray srcBase64 = srcBuf.buffer().toBase64();
// Destination
QByteArray dstBase64 = srcBase64;
QBuffer dstBuf;
dstBuf.buffer() = QByteArray::fromBase64(dstBase64);
QImage dst;
dst.load(&dstBuf, "PNG");
qDebug() << (dst==src);
Q_ASSERT(dst==src);
}