0

I want to upload a PNG image with the Imgur API. When I converted a test image (png) to Base64, I got an error that it was not a valid file type. Then I took the test image from the Imgur API documentation (R0lGODlhAQABAIAAAAAAAP//yH5BAEAAAAALAAAABAAEAAAIBRAA7), which worked for an upload, converted it to a "real" image via a converter and tested a Base64 conversion with it. However, I get a different Base64 string (R0lGODlhAQABAOKCrAAAAAAAw7/Dv8O/IcO5BAEAAAAALAAAAAABAAEAAAIBRAA7). Code snippet:

    QNetworkAccessManager *manager = new QNetworkAccessManager(this);

    QUrl url("https://api.imgur.com/3/image");
    QNetworkRequest request(url);

    request.setRawHeader("Authorization", "Client-ID <hereIsTheClientID>");
    request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");

    QFile image ("C:/Users/pietr/Desktop/image.gif"); // Result from converting example Base64 from Imgur API-Docs - this file can be read by photo viewers
    image.open(QIODevice::ReadOnly);
    QTextStream in (&image);
    QByteArray imageArray = in.readAll().toUtf8().toBase64();
    qDebug() << "Image data:" << imageArray;

    QUrlQuery params;
    params.addQueryItem("image", imageArray);

    connect(manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(replyFinished(QNetworkReply*)));

    manager->post(request, params.query().toUtf8());

But the reply is...

    {
        "data":
        {
            "error":
            {
                "code":1003,
                "message":"File type invalid (2)",
                "type":"ImgurException",
                "exception":[]},"request":"\/3\/image",
                "method":"POST"
            },
        "success":false,
        "status":400
    }

Am I making a mistake with the Base64 convert? Why do I get a different value out of the same images?

Bamp
  • 25
  • 5

1 Answers1

0

The image is not sent in the query but as form-data. Using an old answer and applied in your case the solution is:

#include <QCoreApplication>
#include <QFile>
#include <QHttpMultiPart>
#include <QNetworkAccessManager>
#include <QNetworkReply>

QHttpMultiPart *buildMultpart(const QVariantMap & data, const QMap<QString, QString> filenames){

    QHttpMultiPart *multipart = new QHttpMultiPart(QHttpMultiPart::FormDataType);
    QVariantMap::const_iterator i_data = data.constBegin();
    while (i_data != data.constEnd()) {
        QHttpPart postpart;
        postpart.setHeader(QNetworkRequest::ContentDispositionHeader, QString("form-data; name=\"%1\"").arg(i_data.key()));
        postpart.setBody(i_data.value().toByteArray());
        multipart->append(postpart);
        ++i_data;
    }
    QMap<QString, QString>::const_iterator i_filenames = filenames.constBegin();
    while (i_filenames != filenames.constEnd()) {

        QFile *file = new QFile(i_filenames.value());
        if(!file->open(QIODevice::ReadOnly)){
            delete  file;
            continue;
        }
        QHttpPart postpart;
        postpart.setHeader(QNetworkRequest::ContentDispositionHeader,
                           QString("form-data; name=\"%1\"; filename=\"%2\"")
                           .arg(i_filenames.key(), file->fileName()));
        postpart.setBodyDevice(file);
        multipart->append(postpart);
        file->setParent(multipart);
        ++i_filenames;
    }
    return multipart;
}

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    const QString CLIENT_ID = QLatin1String("{{clientId}}");
    const QString API_URL = QLatin1String("https://api.imgur.com");

    QNetworkAccessManager manager;

    QNetworkRequest request;
    QUrl url(API_URL);
    url.setPath("/3/upload");
    request.setUrl(url);
    request.setRawHeader("Authorization", ("Client-ID "+ CLIENT_ID).toUtf8());
    QMap<QString, QString> filenames;
    filenames["image"] = "C:/Users/pietr/Desktop/image.gif";
    QHttpMultiPart *multipart = buildMultpart({}, filenames);
    QNetworkReply *reply = manager.post(request, multipart);
    multipart->setParent(reply);
    QObject::connect(reply, &QNetworkReply::finished, [reply](){
        if(reply->error() == QNetworkReply::NoError){
            qDebug().noquote() << reply->readAll();
        }
        else{
            qDebug() << reply->error() << reply->errorString();
        }
        reply->deleteLater();
        QCoreApplication::quit();
    });
    return a.exec();
}

Output:

{"status":200,"success":true,"data":{"id":"iT63Heu","deletehash":"JRIdjdWP7lMhzuG","account_id":null,"account_url":null,"ad_type":null,"ad_url":null,"title":null,"description":null,"name":"","type":"image/gif","width":100,"height":75,"size":6166,"views":0,"section":null,"vote":null,"bandwidth":0,"animated":false,"favorite":false,"in_gallery":false,"in_most_viral":false,"has_sound":false,"is_ad":false,"nsfw":null,"link":"https://i.imgur.com/iT63Heu.gif","tags":[],"datetime":1634600948,"mp4":"","hls":""}}

If you want to use base64 then change to:

// ...
request.setRawHeader("Authorization", ("Client-ID "+ CLIENT_ID).toUtf8());
QVariantMap data;
QFile image("C:/Users/pietr/Desktop/image.gif");
if(image.open(QIODevice::ReadOnly)){
    data["image"] = image.readAll().toBase64();
    data["type"] = "base64";
    image.close();
}
QHttpMultiPart *multipart = buildMultpart(data, {});
QNetworkReply *reply = manager.post(request, multipart);
// ...
eyllanesc
  • 235,170
  • 19
  • 170
  • 241
  • There is no function named "buildMultpart". – Bamp Nov 13 '21 at 19:52
  • @Bamp See QHttpMultiPart *buildMultpart(const QVariantMap & data, const QMap filenames){ – eyllanesc Nov 13 '21 at 19:56
  • I use Qt5 and I haven't any member like this. – Bamp Nov 13 '21 at 20:04
  • @Bamp I have created it, it is in the first code of my answer. – eyllanesc Nov 13 '21 at 20:06
  • Oh, I overlooked it... But it still doesn't work. The anwser: `{\"data\":{\"error\":\"Invalid URL (--boundary_.oOo._WYpbiR+sSXxyfEAzLx8X3Dq6QRYTX2cM\\r\\nContent-Disposition: form-data; name=\\\"image\\\"\\r\\n\\r\\nR0lGODlhEAL3AHAA [here's more and more of this unreadable stuff] cJoUvYtJkwSxjzGYkAAADs=\\r\\n--boundary_.oOo._WYpbiR+sSXxyfEAzLx8X3Dq6QRYTX2cM\\r\\nContent-Disposition: form-data; name=\\\"type\\\"\\r\\n\\r\\nbase64\\r\\n--boundary_.oOo._WYpbiR+sSXxyfEAzLx8X3Dq6QRYTX2cM--\\r\\n)\",\"request\":\"\\/3\\/image\",\"method\":\"POST\"},\"success\":false,\"status\":400}` – Bamp Nov 13 '21 at 21:05
  • @Bamp mmm, some wrong configuration you must have. I have tested my solutions and they work correctly. – eyllanesc Nov 13 '21 at 21:07
  • I've tested the upload with base64. Tomorrow I'll test the other way. – Bamp Nov 13 '21 at 21:32