Отправка изображения на FTP-сервер из буфера gchar (libcurl) - PullRequest
2 голосов
/ 26 февраля 2012

Я разрабатываю приложение для Linux, запрограммированное на C, которое обрабатывает изображения gdk pixbuf и затем должно отправить их на удаленный сервер через ftp (libcurl). Изображения сохраняются в буфере gchar с gdk_pixbuf_save_to_buffer .

Проблема в том, что я не знаю, как использовать данные в этом буфере вместе с libcurl read callback function для правильной отправки изображения на удаленный сервер. Все мои попытки до сих пор приводили к получению случайных байтов в результирующий файл.

Существует пример функции обратного вызова чтения libcurl, которая выглядит следующим образом:

static size_t read_callback(void *ptr, size_t size, size_t nmemb, void *stream)
{
    size_t retcode = fread(ptr, size, nmemb, stream);
    return retcode;
} 

Мне нужно сделать свою собственную функцию обратного вызова, которая получает буфер gchar в качестве входных данных вместо файлового потока и читает из него размер * nmemb байтов и сохраняет его в * ptr.

Это связано с моим предыдущим вопросом .

1 Ответ

2 голосов
/ 27 февраля 2012

read_callback() - это функция, которую CURL вызывает, когда необходимо получить данные, которые будут загружены на сервер. Представьте, что read_callback() является чем-то похожим на fread(). При вызове он выполняет любое необходимое voodoo-mumbo-jumbo, но в конце загружаемые данные должны храниться в буфере *ptr, который является внутренним буфером curl. Для вашего буфера в памяти memcpy() будет отлично работать как тело read_callback(), так что вам совсем не нужен настоящий fread().

size * nmemb говорит вам, как большой буферный curl зарезервирован для одного куска данных. Последний void* - это указатель, который был установлен параметром CURLOPT_READDATA - это указатель типа «делай все, что тебе нужно», так что он может указывать на структуру, содержащую данные, которые ты загружаешь, и некоторая дополнительная информация, например текущий прогресс.

Вы можете использовать это как образец:

#include <gdk-pixbuf/gdk-pixbuf.h>
#include <stdlib.h>
#include <curl/curl.h>
#include <string.h>

struct transfer
{
    gchar *buf;
    gsize total;
    size_t uploaded;
};

static size_t read_callback(void *ptr, size_t size, size_t nmemb, void *data)
{
    struct transfer * tr = data;
    size_t left = tr->total - tr->uploaded;
    size_t max_chunk = size * nmemb;
    size_t retcode = left < max_chunk ? left : max_chunk;

    memcpy(ptr, tr->buf + tr->uploaded, retcode); // <-- voodoo-mumbo-jumbo :-)

    tr->uploaded += retcode;  // <-- save progress
    return retcode;
} 

int main()
{
    GdkPixbuf * gbuffer = NULL;
    GError * error = NULL;
    gchar * buffer;
    gsize size;
    g_type_init();
    gbuffer = gdk_pixbuf_new_from_file("g.png", &error);
    gdk_pixbuf_save_to_buffer(gbuffer, &buffer, &size, "jpeg", &error, NULL);

    struct transfer tr = {buffer, size, 0};

    CURL *easyhandle = curl_easy_init();
    curl_easy_setopt(easyhandle, CURLOPT_READFUNCTION, read_callback); 
    curl_easy_setopt(easyhandle, CURLOPT_READDATA, &tr); // <-- this will be *data in read_callback()
    curl_easy_setopt(easyhandle, CURLOPT_UPLOAD, 1L); 
    curl_easy_setopt(easyhandle, CURLOPT_URL, "http://example.com/upload.php");
    CURLcode rc = curl_easy_perform(easyhandle);
}
...