QML: how to upload a photo from Camera to a web server using XMLHttpRequest
-
Hi,
I'm using Qt 5.3 to build my first QML app.
I have a Qt Quick application which takes a photo using Camera, from the QtMultimedia module.
I would like to upload this image on a web server using XMLHttpRequest, through a POST request. The API I have to use requires multi-part mime header.
How can I do that? Is it possible to build this request using QML only or do I need a bit of C++?My image is stored in an Image type (I can display it, it works) :
@Image {
id: photo
}@My upload function looks like this, but is incomplete at the moment:
@function uploadImage(server, callback) {
var req = new XMLHttpRequest();
req.onreadystatechange = function() {
if (req.readyState == XMLHttpRequest.HEADERS_RECEIVED) {
console.log("Debug: header: " + req.getAllResponseHeaders ());
} else if (req.readyState == XMLHttpRequest.DONE) {
console.log("Debug: xml response: " + req.responseText);
}
}req.open("POST", server + "/api/cAddImage"); // here I don't know to to build the request to send 'photo'??? req.setRequestHeader(???); req.send(???); }@
Thanks in advance,
Best regards -
Hi and welcome to devnet,
Maybe "this":http://stackoverflow.com/questions/9713058/sending-post-data-with-a-xmlhttprequest will help
-
Thank you for your answer.
I found this post before and it works to send text data.
E.g. , here is my code to send credentials to log on the server:@req.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
req.send("username=" + username + "&password=" + password);@But I cannot find the right syntax to send an image???
-
May be using FormData. Never tried though.
-
Here is my solution: image uploading is performed by a separate C++ class, using QNetworkAccessManager:
@#ifndef IMAGEUPLOADER_H
#define IMAGEUPLOADER_H#include <QDebug>
#include <QFile>
#include <QFileInfo>
#include <QHttpMultiPart>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QNetworkRequest>
#include <QString>class ImageUploader: public QObject {
Q_OBJECTpublic:
ImageUploader(QObject* parent = 0)
: QObject (parent)
, m_networkAccessManager(NULL)
, m_networkReply (NULL) {
m_networkAccessManager = new QNetworkAccessManager(this);
}public slots:
void uploadImage(const QString& imageFilename) {
QFileInfo fileInfo(imageFilename);
QFile* file = new QFile(imageFilename);
if (!file->open(QIODevice::ReadWrite)) {
emit imageUploaded(999, "Image not found");
return;
}emit imageUploaded(-1, "Try to upload image to server, please wait..."); QHttpMultiPart* multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType); QHttpPart imagePart; imagePart.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("image/jpeg")); imagePart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant(QString("form-data; name=\"image\"; filename=\"%1\"").arg(fileInfo.fileName()).toLatin1())); imagePart.setBodyDevice(file); file->setParent(multiPart); multiPart->append(imagePart); QNetworkRequest request("http://www.myserver.com/uploadImage"); m_networkReply = m_networkAccessManager->post(request, multiPart); multiPart->setParent(m_networkReply); connect(m_networkReply, SIGNAL(finished()), this, SLOT(uploadImageFinished()));
private slots:
void uploadImageFinished() {
QString xmlReply = QString(m_networkReply->readAll());
delete m_networkReply;
qDebug() << xmlReply;
// here, you can parse the reply from the server...
emit imageUploaded(0, "Image successfully uploaded");
}signals:
// errorCode = -1 : start image uploading
// 0 : success
// >0: error
void imageUploaded(int errorCode, const QString& errorMessage);private:
QNetworkAccessManager* m_networkAccessManager;
QNetworkReply* m_networkReply;
};#endif // IMAGEUPLOADER_H
@To access the "image uploader" object from QML, we need to perform the binding, for example, in the main...
@#include <QApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include "ImageUploader.h"int main(int argc, char* argv[])
{
QApplication app(argc, argv);QQmlApplicationEngine engine; ImageUploader imageUploader; engine.rootContext()->setContextProperty("imageUploader", &imageUploader); engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); return app.exec();
}
@Finally, uploadImage() method is directly used in the QML code which can also retrieve signal emitted by the C++ code. Something like that...
@import QtQuick 2.0
import QtMultimedia 5.3Rectangle {
id: pageCaptureConnections { // to receive "imageUploaded" signal from the C++ code target: imageUploader onImageUploaded: { console.log("onImageUploaded: errorCode=" + errorCode + " errorMessage=" + errorMessage); } } Camera { id: camera imageCapture { onImageSaved: { // call the C++ method to upload image (filename is 'path') imageUploader.uploadImage(path); } } } VideoOutput { id: videoOutput source: camera anchors.fill: parent focus : visible fillMode: VideoOutput.PreserveAspectCrop }
}
@ -
I can not get the code to work. Maybe the code of uploadimage.cpp is missing? Anybody can help me? Thanks in advance
-
I can not get the code to work. Maybe the code of uploadimage.cpp is missing? Anybody can help me? Thanks in advance