Отправка фото через тг бота с++
Пишу тг бота на с++, используя эту библиотеку для бота и эту для работы с изображениями. Бот должен принимать фото, преобразовывать его в негатив и отправлять обратно пользователю. Вот мой код:
#include <tgbot/tgbot.h>
#include <curl/curl.h>
#include "CImg.h"
using namespace cimg_library;
using namespace TgBot;
using namespace std;
const string token = "token";
TgBot::Bot bot(token);
void download_file(const string& url, const string& output_filename){
CURL* curl = curl_easy_init();
if(curl){
FILE* fp = fopen(output_filename.c_str(), "wb");
if(fp){
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, 0);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
CURLcode res = curl_easy_perform(curl);
fclose(fp); // Закрываем файл
if(res != CURLE_OK)
fprintf(stderr, "curl_easy_perform() failed: %s\n",
curl_easy_strerror(res));
}
curl_easy_cleanup(curl);
}
}
int main(){
bot.getEvents().onAnyMessage([&bot](Message::Ptr m){
static uint8_t wherePhoto;
if(m->chat->type != TgBot::Chat::Type::Private) return;
if(m->text == "/start"){
wherePhoto = 0;
bot.getApi().sendMessage(m->chat->id, "Добро пожаловать в бота - ретушера.\n" "отправьте фото и выберите эффект для наложения");
return;
}
if(m->text == "/negative"){
if(!wherePhoto) return;
const CImg<unsigned char> img1("save.jpg"),
img2 = -img1;
img2.save_jpeg("save_n.jpg");
bot.getApi().sendPhoto(m->chat->id, "save_n.jpg");
wherePhoto = 0;
}
if(m->photo.size()){
string Url = "https://api.telegram.org/file/bot" + token + "/" + bot.getApi().getFile(m->photo[0]->fileId)->filePath;
download_file(Url,"save.jpg");
bot.getApi().sendMessage(m->chat->id, "Список доступных преобразований:\n"
"/negative"
);
wherePhoto = 1;
return;
} else {
bot.getApi().sendMessage(m->chat->id, "Отправьте фото для наложения эффектов");
return;
}
});
try {
TgLongPoll longPoll(bot);
while (true) {
longPoll.start();
cout << "LP started\n";
}
} catch (exception& e) {
cerr << e.what() << endl;
}
return 0;
}
По задумке отправленное фото должно сохраняться на компе, преобразовываться в негатив и отправляться обратно пользователю (а потом само собой удаляться с компа). Проблема возникает при отправке: здесь функция bot.getApi().sendPhoto(m->chat->id, "save_n.jpg"); не срабатывает, тк нужен либо url либо id файла либо отправка с помощью multipart/form-data (так написано в документации), но я не понимаю, как перейти от локального файла "save_n.jpg" к чему-то, что имеет ссылку. Подскажите, каким образом это лучше реализовать? Можно ли обойтись силами curl?
Ответы (2 шт):
Обновление
Ещё раз перечитав ваш вопрос, я прихожу к выводу, что мой ответ не вполне отвечает на собственно вопрос, как превратить бинарный файл в формат multipart/form-data и интегрировать полученные данные с вызовом bot.getApi().sendPhoto(). Наверное, для этого надо покопаться в документации к самому боту, но у меня к сожалению нет для этого ни времени, ни желания. Поскольку сам бот, похоже, использует для работы с HTTP именно библиотеку libcurl, сам исходный ответ я на всякий случай оставлю, вдруг он чем-нибудь да поможет. Но использовать библиотеку libcurl именно для генерации данных в формате multipart/form-data из бинарного файла, в отрыве от собственно вызова curl_easy_perform(), насколько мне известно, нельзя.
Конечно можно, libcurl - это очень могучая библиотека. Для этого вам понадобятся функции curl_mime_init() и curl_mime_filedata() (по ссылкам можно также посмотреть примеры использования). Код для отправки файла будет выглядеть примерно так (не проверял!):
void upload_file(const string& url, const string& output_filename){
curl_mime *mime;
curl_mimepart *part;
CURL* curl = curl_easy_init();
if(curl){
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
mime = curl_mime_init(curl);
part = curl_mime_addpart(mime);
curl_mime_filedata(part, output_filename.c_str());
// Во всех примерах задают какое-то имя для mime part, наверное это необходимо :)
curl_mime_name(part, "image");
curl_easy_setopt(curl, CURLOPT_MIMEPOST, mime);
CURLcode res = curl_easy_perform(curl);
if(res != CURLE_OK)
fprintf(stderr, "curl_easy_perform() failed: %s\n",
curl_easy_strerror(res));
curl_mime_free(mime);
curl_easy_cleanup(curl);
}
}
Весь файловый ввод/вывод происходит уже внутри libcurl, и код ошибки, если таковая вдруг произойдёт, вернётся при вызове curl_easy_perform().
P.S. Использованные функции доступны в libcurl начиная с версии 7.56, ранее для получения подобной функциональности надо было использовать функцию curl_formadd().
Проблему решил. Необходимо использовать функцию TgBot::InputFile::fromFile(). Она конвертирует фото в формат, пригодный к отправке через sendPhoto().
auto input_f = TgBot::InputFile::fromFile("path_to_photo.jpg", "image/jpg");
bot.getApi().sendPhoto(m->chat->id, input_f);