0

Before I write the details, here's what I want to achieve.

  1. Search for some images on pixabay (searching for yellow flowers in this case)
  2. When I post this query, I will get json array with details of images.
  3. Parse the data and store array data.
  4. Now send subsequent curl request to retrieve/download images using URLs present in the array data.

Current code :

I was able to achieve 1, 2 and 3. 3rd implementation I have done (as of now) by store data locally in a file and parsing it.

I am stuck at 4th point.

Posting one of the element from array data :

   "hits":[
      {
         "id":2295434,
         "pageURL":"https://pixabay.com/photos/spring-bird-bird-tit-spring-blue-2295434/",
         "type":"photo",
         "tags":"spring bird, bird, tit",
         "previewURL":"https://cdn.pixabay.com/photo/2017/05/08/13/15/spring-bird-2295434_150.jpg",
         "previewWidth":150,
         "previewHeight":99,
         "webformatURL":"https://pixabay.com/get/gc323739b5570ab1afac9cff34f0ed431beffcf004e0660fcaff96a7b1780933e31c982b26cdb3234c4a757a9e7e8b824bda6059340ead3c6b755f1265f7ace52_640.jpg",
         "webformatWidth":640,
         "webformatHeight":426,
         "largeImageURL":"https://pixabay.com/get/g58a377c4cffe13bffd15cb7b455ecec08329352a443689296c5f15565b3a7f11bcd5ec6e4d2945bb3d32b2a63ee33d6c9a9925119944d128cab4bca663f87620_1280.jpg",
         "imageWidth":5363,
         "imageHeight":3575,
         "imageSize":2938651,
         "views":488125,
         "downloads":261832,
         "collections":1911,
         "likes":1846,
         "comments":221,
         "user_id":334088,
         "user":"JillWellington",
         "userImageURL":"https://cdn.pixabay.com/user/2018/06/27/01-23-02-27_250x250.jpg"
      }
]

main.cc

#include "baseurihandler/base_uri_handler_pixabay.h"

#include "json_parser.h"
#include "download_image.h"

#include <stdio.h>
#include <iostream>
#include <curl/curl.h>

#include <iostream>
#include <chrono>
#include <string>
#include <thread>
#include <vector>

void JsonParser();

int main() {
    CURL *curl;
    CURLcode res;

    std::vector<std::pair<std::string, std::string>> query_param;
    query_param.push_back(std::make_pair("q", "yellow+flowers"));
    query_param.push_back(std::make_pair("image_type", "photo"));

    std::string s;

    baseuri::PixabayURIHandler pixabay_uri_handler;

    pixabay_uri_handler.SetQueryParameters(query_param);

    //auto str = pixabay_uri_handler.GetURI();
    auto str = std::string("https://pixabay.com/api/?key=xxxxxxx-xxxxxxxxxxx&q=yellow+flowers&image_type=photo");
    std::cout << str << std::endl;

    curl = curl_easy_init();
    if(curl) {

        curl_easy_setopt(curl, CURLOPT_URL, str.c_str());

        /* example.com is redirected, so we tell libcurl to follow redirection */
        curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, baseuri::PixabayURIHandler::CurlWrite_CallbackFunc_StdString);
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, &pixabay_uri_handler);

        /* Perform the request, res will get the return code */
        res = curl_easy_perform(curl);
        /* Check for errors */
        if (res != CURLE_OK)
            fprintf(stderr, "curl_easy_perform() failed: %s\n",
                    curl_easy_strerror(res));

        /* always cleanup */
        curl_easy_cleanup(curl);
    }

    //std::cout << pixabay_uri_handler.GetResultJsonString() << std::endl;
    std::cout << "calling jsonparser.. " << std::endl;
    JsonParser(); //This will return vec of URLs - TBD

    char *jpg_test = "https://pixabay.com/get/g58a377c4cffe13bffd15cb7b455ecec08329352a443689296c5f15565b3a7f11bcd5ec6e4d2945bb3d32b2a63ee33d6c9a9925119944d128cab4bca663f87620_1280.jpg";
    if (!download_jpeg(jpg_test))
    {
        printf("!! Failed to download file!\n" );
        return -1;
    }

    return 0;
}

Implementation of download_jpeg:

#include <stdio.h>
#include <curl/curl.h>

size_t callbackfunction(void *ptr, size_t size, size_t nmemb, void* userdata)
{
    FILE* stream = (FILE*)userdata;
    if (!stream)
    {
        printf("!!! No stream\n");
        return 0;
    }

    size_t written = fwrite((FILE*)ptr, size, nmemb, stream);
    return written;
}

bool download_jpeg(char* url)
{
    FILE* fp = fopen("out.jpg", "wb");
    if (!fp)
    {
        printf("!!! Failed to create file on the disk\n");
        return false;
    }

    CURL* curlCtx = curl_easy_init();
    curl_easy_setopt(curlCtx, CURLOPT_URL, url);
    curl_easy_setopt(curlCtx, CURLOPT_WRITEDATA, fp);
    curl_easy_setopt(curlCtx, CURLOPT_WRITEFUNCTION, callbackfunction);
    curl_easy_setopt(curlCtx, CURLOPT_FOLLOWLOCATION, 1);

    CURLcode rc = curl_easy_perform(curlCtx);
    if (rc)
    {
        printf("!!! Failed to download: %s\n", url);
        return false;
    }

    long res_code = 0;
    curl_easy_getinfo(curlCtx, CURLINFO_RESPONSE_CODE, &res_code);
    if (!((res_code == 200 || res_code == 201) && rc != CURLE_ABORTED_BY_CALLBACK))
    {
        printf("!!! Response code: %d\n", res_code);
        return false;
    }

    curl_easy_cleanup(curlCtx);

    fclose(fp);

    return true;
}

What is the correct way of forming the subsequent URL for downloading images? Instead of directly sending largeImageURL to download_jpeg(), I tried adding api key as query parameter together with largeImageURL value, but did not help -- received 400 response code.

There's nothing in the pixabay documentation that is helping.

1 Answers1

1

curl easy handles do not share session states without a special additional actions. But each individual one keeps a session state and can reuse it until curl_easy_cleanup() is called. You use another curl easy handle in download_jpeg - this is the reason of the error "This URL is invalid or has expired."

The easiest fix is reusing the curl easy handle.

bool download_jpeg(CURL* curl, const char* url)
{
    FILE* fp = fopen("out.jpg", "wb");
    if (!fp)
    {
        printf("!!! Failed to create file on the disk\n");
        return false;
    }

    curl_easy_setopt(curl, CURLOPT_URL, url);
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, callbackfunction);
    curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);

    CURLcode rc = curl_easy_perform(curl);
    if (rc)
    {
        printf("!!! Failed to download: %s\n", url);
        return false;
    }

    long res_code = 0;
    curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &res_code);
    if (!((res_code == 200 || res_code == 201) && rc != CURLE_ABORTED_BY_CALLBACK))
    {
        printf("!!! Response code: %d\n", res_code);
        return false;
    }

    fclose(fp);

    return true;
}

int main() {
    CURL *curl;
    CURLcode res;

    std::vector<std::pair<std::string, std::string>> query_param;
    query_param.push_back(std::make_pair("q", "yellow+flowers"));
    query_param.push_back(std::make_pair("image_type", "photo"));

    std::string s;

    baseuri::PixabayURIHandler pixabay_uri_handler;

    pixabay_uri_handler.SetQueryParameters(query_param);

    //auto str = pixabay_uri_handler.GetURI();
    auto str = std::string("https://pixabay.com/api/?key=xxxxxxx-xxxxxxxxxxx&q=yellow+flowers&image_type=photo");
    std::cout << str << std::endl;

    curl = curl_easy_init();
    if(curl) {
        curl_easy_setopt(curl, CURLOPT_COOKIEFILE, "");
        curl_easy_setopt(curl, CURLOPT_URL, str.c_str());

        curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, baseuri::PixabayURIHandler::CurlWrite_CallbackFunc_StdString);
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, &pixabay_uri_handler);

        /* Perform the request, res will get the return code */
        res = curl_easy_perform(curl);
        /* Check for errors */
        if (res != CURLE_OK)
            fprintf(stderr, "curl_easy_perform() failed: %s\n",
                    curl_easy_strerror(res));
    }

    //std::cout << pixabay_uri_handler.GetResultJsonString() << std::endl;
    std::cout << "calling jsonparser.. " << std::endl;
    JsonParser(); //This will return vec of URLs - TBD

    const char* jpg_test = "https://pixabay.com/get/g58a377c4cffe13bffd15cb7b455ecec08329352a443689296c5f15565b3a7f11bcd5ec6e4d2945bb3d32b2a63ee33d6c9a9925119944d128cab4bca663f87620_1280.jpg";
    const bool rv = download_jpeg(curl, jpg_test);
    if (!rv)
        printf("!! Failed to download file!\n" );

    /* always cleanup */
    curl_easy_cleanup(curl);

    return rv ? -1 : 0;
}

The original download_jpeg() has the issues:

  •  curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
    

    must pass long 1L

     curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
    
  • Memory leaks - curl_easy_cleanup(curlCtx); is not called if error occurs, due to eraly return. The new version does not create new curl easy handler, thus there is no a memory leak.

The main has been updated:

  • curl_easy_setopt(curl, CURLOPT_COOKIEFILE, "") activates the cookie engine.
  • curl handle is passed to download_jpeg and reused there.
  • curl_easy_cleanup(curl); has been moved to the end.
  • String literals are const char arrays in C++, thus const char* jpg_test = ""; must be used.

If you need use several curl easy handles in a single session, follow the manual Sharing between easy handles, or use a single curl multi handle with many curl easy handles.

273K
  • 29,503
  • 10
  • 41
  • 64
  • Information is certainly helpful but I am still getting same error code of 400 after I made suggested changes! which means I am not getting correct URL to download the image. – Vineet Dwivedi Jun 14 '22 at 20:06
  • Could it be that when I go pixabay documentation page, it only shows documentation on searching images but nothing on the download of individual image returned through initial query and hence I cannot download images this way ? -- referring this link : https://pixabay.com/api/docs/ – Vineet Dwivedi Jun 14 '22 at 20:17
  • I don't use pixabay. I hoped session cookies after the initial start request should have given access. If it does not work, then user authentication is required on the second request. You could ask the question to their support team. – 273K Jun 14 '22 at 20:29
  • Nope! dint help. still giving 400 response code. – Vineet Dwivedi Jun 14 '22 at 20:50
  • You were confusing me! It is working well, even with no cookies. The link `jpg_test` has just expired. You should re-request JSON and renew the link `jpg_test`. I hoped you did it, but you did not! – 273K Jun 15 '22 at 00:34
  • sorry! that was my bad. You are right. When I updated jpg_test, it worked well. Marking the ans as resolved and we can close this thread. Thanks a ton! – Vineet Dwivedi Jun 15 '22 at 09:10