diff --git a/KShare.pro b/KShare.pro index 561d5ac..708d05b 100644 --- a/KShare.pro +++ b/KShare.pro @@ -51,7 +51,8 @@ SOURCES += main.cpp\ screenareaselector/screenareaselector.cpp \ recording/recordingpreview.cpp \ recording/recordingcontroller.cpp \ - recording/recordingformats.cpp + recording/recordingformats.cpp \ + formats.cpp HEADERS += mainwindow.hpp \ cropeditor/cropeditor.hpp \ @@ -84,7 +85,8 @@ HEADERS += mainwindow.hpp \ screenareaselector/screenareaselector.hpp \ recording/recordingpreview.hpp \ recording/recordingcontroller.hpp \ - recording/recordingformats.hpp + recording/recordingformats.hpp \ + formats.hpp mac { SOURCES += $$PWD/platformspecifics/mac/macbackend.cpp diff --git a/formats.cpp b/formats.cpp new file mode 100644 index 0000000..d03ea55 --- /dev/null +++ b/formats.cpp @@ -0,0 +1,63 @@ +#include + +QString formats::normalFormatName(formats::Normal format) { + switch (format) { + case Normal::JPG: + return "JPG"; + break; + case Normal::PNG: + return "PNG"; + break; + default: + return QString(); + break; + } +} + +formats::Normal formats::normalFormatFromName(QString format) { + if (format.toLower() == "jpg") return Normal::JPG; + if (format.toLower() == "jpeg") return Normal::JPG; + if (format.toLower() == "png") return Normal::PNG; + return Normal::None; +} + +QString formats::normalFormatMIME(formats::Normal format) { + switch (format) { + case Normal::JPG: + return "image/jpeg"; + break; + case Normal::PNG: + return "image/png"; + break; + default: + return QString(); + break; + } +} + +QString formats::recordingFormatName(formats::Recording format) { + switch (format) { + case Recording::GIF: + return "GIF"; + break; + default: + return QString(); + break; + } +} + +formats::Recording formats::recordingFormatFromName(QString format) { + if (format.toLower() == "gif") return Recording::GIF; + return Recording::None; +} + +QString formats::recordingFormatMIME(formats::Recording format) { + switch (format) { + case Recording::GIF: + return "image/gif"; + break; + default: + return QString(); + break; + } +} diff --git a/formats.hpp b/formats.hpp new file mode 100644 index 0000000..fa22c52 --- /dev/null +++ b/formats.hpp @@ -0,0 +1,17 @@ +#ifndef FORMATS_HPP +#define FORMATS_HPP + +#include + +namespace formats { +enum class Normal { PNG, JPG, None }; +QString normalFormatName(Normal format); +Normal normalFormatFromName(QString format); +QString normalFormatMIME(Normal format); + +enum class Recording { GIF, None }; +QString recordingFormatName(Recording format); +Recording recordingFormatFromName(QString format); +QString recordingFormatMIME(Recording format); +} +#endif // FORMATS_HPP diff --git a/formatter.cpp b/formatter.cpp index 11cac10..9f53a16 100644 --- a/formatter.cpp +++ b/formatter.cpp @@ -3,7 +3,7 @@ #include #include -QString formatter::format(QString toFormat) { +QString formatter::format(QString toFormat, QString ext) { QRegExp dateRegex("%\\((.+)\\)date"); dateRegex.indexIn(toFormat); QStringList capturedTexts(dateRegex.capturedTexts()); @@ -12,5 +12,6 @@ QString formatter::format(QString toFormat) { for (int i = 0; i < capturedTexts.length(); i += 2) { formatted = formatted.replace(capturedTexts.at(i), date.toString(capturedTexts.at(i + 1))); } + formatted = formatted.replace(QRegExp("%(?!%)ext"), ext); return formatted; } diff --git a/formatter.hpp b/formatter.hpp index c537ff9..797c2ec 100644 --- a/formatter.hpp +++ b/formatter.hpp @@ -5,7 +5,7 @@ #include namespace formatter { -QString format(QString toFormat); +QString format(QString toFormat, QString ext); } #endif // FORMATTER_HPP diff --git a/main.cpp b/main.cpp index 1e2d6f1..5c12ede 100644 --- a/main.cpp +++ b/main.cpp @@ -2,7 +2,9 @@ #include "screenshotutil.hpp" #include #include +#include #include +#include #include #include #include @@ -56,7 +58,6 @@ int main(int argc, char *argv[]) { } verbose = parser.isSet(v); - MainWindow w; Worker::init(); a.connect(&a, &QApplication::aboutToQuit, Worker::end); diff --git a/mainwindow.cpp b/mainwindow.cpp index 16e2eda..6c4992b 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -91,15 +91,16 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWi addHotkeyItem("Color picker", "picker", [] { ColorPickerScene::showPicker(); }); addHotkeyItem("Stop Recording", "recordingstop", [&] { controller->end(); }); addHotkeyItem("Start Recording", "recordingstart", [&] { - auto f = static_cast( - settings::settings().value("recording/format", (int)RecordingFormats::None).toInt()); - if (f == RecordingFormats::None) return; + auto f + = static_cast(settings::settings().value("recording/format", (int)formats::Recording::None).toInt()); + if (f >= formats::Recording::None) return; RecordingContext *ctx = new RecordingContext; RecordingFormats *format = new RecordingFormats(f); ctx->consumer = format->getConsumer(); ctx->finalizer = format->getFinalizer(); ctx->validator = format->getValidator(); ctx->format = format->getFormat(); + ctx->anotherFormat = format->getAnotherFormat(); controller->start(ctx); }); @@ -107,11 +108,16 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWi ui->hideToTray->setChecked(settings::settings().value("hideOnClose", true).toBool()); ui->captureCursor->setChecked(settings::settings().value("captureCursor", true).toBool()); - for (int i = 0; i < RecordingFormats::None; i++) { - ui->formatBox->addItem(RecordingFormats::getExt(static_cast(i))); + for (int i = 0; i < (int)formats::Recording::None; i++) { + ui->formatBox->addItem(formats::recordingFormatName(static_cast(i))); } + + for (int i = 0; i < (int)formats::Normal::None; i++) { + ui->imageFormatBox->addItem(formats::normalFormatName(static_cast(i))); + } + ui->formatBox->addItem("None"); - ui->formatBox->setCurrentIndex(settings::settings().value("recording/format", (int)RecordingFormats::None).toInt()); + ui->formatBox->setCurrentIndex(settings::settings().value("recording/format", (int)formats::Recording::None).toInt()); } MainWindow::~MainWindow() { @@ -219,3 +225,7 @@ void MainWindow::on_captureCursor_clicked(bool checked) { void MainWindow::on_formatBox_currentIndexChanged(int index) { settings::settings().setValue("recording/format", index); } + +void MainWindow::on_imageFormatBox_currentIndexChanged(const QString &arg1) { + settings::settings().setValue("imageformat", arg1); +} diff --git a/mainwindow.hpp b/mainwindow.hpp index e94af32..cbfefa1 100644 --- a/mainwindow.hpp +++ b/mainwindow.hpp @@ -33,8 +33,8 @@ private slots: void on_hideToTray_clicked(bool checked); void on_actionColor_Picker_triggered(); void on_captureCursor_clicked(bool checked); - void on_formatBox_currentIndexChanged(int index); + void on_imageFormatBox_currentIndexChanged(const QString &arg1); public: explicit MainWindow(QWidget *parent = 0); diff --git a/mainwindow.ui b/mainwindow.ui index 8207390..3579434 100644 --- a/mainwindow.ui +++ b/mainwindow.ui @@ -6,8 +6,8 @@ 0 0 - 512 - 412 + 483 + 478 @@ -25,7 +25,10 @@ - + + + + -1 @@ -70,7 +73,7 @@ - + <a href="https://github.com/ArsenArsen/KShare">Source code available free for everyone. Forever.</a> @@ -112,24 +115,31 @@ - - + + - Capture cursor + Recording format - + + + + Still image format + + + + Pressing <X> hides to tray - - + + - Recording format + Capture cursor @@ -140,7 +150,7 @@ 0 0 - 512 + 483 25 diff --git a/recording/recordingcontroller.cpp b/recording/recordingcontroller.cpp index 7dd376e..6542dfd 100644 --- a/recording/recordingcontroller.cpp +++ b/recording/recordingcontroller.cpp @@ -38,7 +38,12 @@ bool RecordingController::end() { preview = 0; WorkerContext *c = new WorkerContext; - c->consumer = [&](QImage) { queue(_context->finalizer()); }; + c->consumer = [&](QImage) { + _QueueContext contx; + contx.arr = _context->finalizer(); + contx.format = _context->anotherFormat; + queue(contx); + }; c->targetFormat = QImage::Format_Alpha8; c->pixmap = QPixmap(0, 0); Worker::queue(c); @@ -48,7 +53,7 @@ bool RecordingController::end() { return true; } -void RecordingController::queue(QByteArray arr) { +void RecordingController::queue(_QueueContext arr) { QMutexLocker l(&lock); uploadQueue.enqueue(arr); } @@ -86,7 +91,10 @@ void RecordingController::timeout() { preview->setTime(QString("%1:%2").arg(QString::number(minute)).arg(QString::number(second)), frame); } else { QMutexLocker l(&lock); - if (!uploadQueue.isEmpty()) UploaderSingleton::inst().upload(uploadQueue.dequeue()); + if (!uploadQueue.isEmpty()) { + auto a = uploadQueue.dequeue(); + UploaderSingleton::inst().upload(a.arr, a.format); + } } } diff --git a/recording/recordingcontroller.hpp b/recording/recordingcontroller.hpp index ca5374d..f35e169 100644 --- a/recording/recordingcontroller.hpp +++ b/recording/recordingcontroller.hpp @@ -12,12 +12,17 @@ #include #include -class RecordingContext { -public: +struct RecordingContext { QImage::Format format; std::function consumer; std::function validator; std::function finalizer; + QString anotherFormat; +}; + +struct _QueueContext { + QByteArray arr; + QString format; }; class RecordingController : public QObject { @@ -30,14 +35,14 @@ public slots: bool start(RecordingContext *context); // Returns false if not running bool end(); - void queue(QByteArray arr); + void queue(_QueueContext arr); private slots: void timeout(); void startWithArea(QRect newArea); private: QMutex lock; - QQueue uploadQueue; + QQueue<_QueueContext> uploadQueue; QRect area; RecordingContext *_context = 0; QTimer timer; diff --git a/recording/recordingformats.cpp b/recording/recordingformats.cpp index 7482973..cb509af 100644 --- a/recording/recordingformats.cpp +++ b/recording/recordingformats.cpp @@ -7,13 +7,14 @@ #include #include #include +#include #include #include #include #include #include -RecordingFormats::RecordingFormats(RecordingFormats::Format f) { +RecordingFormats::RecordingFormats(formats::Recording f) { QString path = QStandardPaths::writableLocation(QStandardPaths::TempLocation); if (path.isEmpty()) { @@ -26,7 +27,7 @@ RecordingFormats::RecordingFormats(RecordingFormats::Format f) { tmpDir.mkdir(name); tmpDir.cd(name); switch (f) { - case GIF: { + case formats::Recording::GIF: { iFormat = QImage::Format_RGBA8888; validator = [] { return true; }; consumer = [&](QImage img) { frames.push_back(img); }; @@ -49,6 +50,7 @@ RecordingFormats::RecordingFormats(RecordingFormats::Format f) { QByteArray data = res.readAll(); return data; }; + anotherFormat = formats::recordingFormatName(f); break; } default: @@ -72,16 +74,6 @@ QImage::Format RecordingFormats::getFormat() { return iFormat; } -QString RecordingFormats::getExt(RecordingFormats::Format f) { - switch (f) { - case None: - return "None"; - break; - case GIF: - return "gif"; - break; - default: - return QString(); - break; - } +QString RecordingFormats::getAnotherFormat() { + return anotherFormat; } diff --git a/recording/recordingformats.hpp b/recording/recordingformats.hpp index cd24185..3a510aa 100644 --- a/recording/recordingformats.hpp +++ b/recording/recordingformats.hpp @@ -5,18 +5,17 @@ #include #include #include +#include #include class RecordingFormats { public: - enum Format { GIF, None }; - RecordingFormats(Format f); + RecordingFormats(formats::Recording f); std::function getConsumer(); std::function getFinalizer(); std::function getValidator(); QImage::Format getFormat(); - - static QString getExt(Format f); + QString getAnotherFormat(); private: std::function consumer; @@ -25,7 +24,7 @@ private: std::vector frames; QImage::Format iFormat; QDir tmpDir; - int frame = 0; + QString anotherFormat; }; #endif // RECORDINGFORMATS_HPP diff --git a/uploaders/customuploader.cpp b/uploaders/customuploader.cpp index 29dbf2f..4d2e97b 100644 --- a/uploaders/customuploader.cpp +++ b/uploaders/customuploader.cpp @@ -7,9 +7,12 @@ #include #include #include +#include #include #include +using formats::normalFormatFromName; +using formats::normalFormatMIME; using std::runtime_error; void error(QString absFilePath, QString err) { @@ -17,12 +20,6 @@ void error(QString absFilePath, QString err) { } CustomUploader::CustomUploader(QString absFilePath) { - types.insert("PNG", "image/png"); // This is a list of supported formats, too - types.insert("GIF", "image/gif"); - types.insert("JPG", "image/jpeg"); - types.insert("JPEG", "image/jpeg"); - types.insert("WEBM", "video/webm"); - types.insert("MP4", "video/mp4"); // Let's go QFile file(absFilePath); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) error(absFilePath, file.errorString()); @@ -74,16 +71,6 @@ CustomUploader::CustomUploader(QString absFilePath) { } } else error(absFilePath, "format provided but not string"); - QJsonValue imageValue = obj["imageformat"]; - if (!imageValue.isString()) { - error(absFilePath, "imageformat not string"); - } - QString imageFormat = imageValue.toString(); - if (imageFormat == "base64" || QRegExp("base64\\([^+]+\\+[^+]+)").exactMatch(imageFormat) - || QRegExp("[^+]+\\+[^+]+").exactMatch(imageFormat)) { - this->iFormat = imageFormat; - } else - error(absFilePath, "imageformat invalid"); QJsonValue bodyValue = obj["body"]; if (rFormat != RequestFormat::PLAIN) { if (bodyValue.isUndefined()) error(absFilePath, "body not set"); @@ -113,6 +100,11 @@ CustomUploader::CustomUploader(QString absFilePath) { if (!fileLimit.isDouble()) error(absFilePath, "fileLimit not double"); limit = fileLimit.toDouble(); } + QJsonValue bool64 = obj["base64"]; + if (!bool64.isNull() && !bool64.isUndefined()) { + if (!bool64.isBool()) error(absFilePath, "base64 must be boolean"); + base64 = bool64.toBool(); + } } QString CustomUploader::name() { @@ -123,10 +115,6 @@ QString CustomUploader::description() { return desc; } -std::tuple CustomUploader::format() { - return std::tuple(getFormatString(false), getFormatString(true)); -} - QString getCType(RequestFormat format, QString plainType) { switch (format) { case RequestFormat::X_WWW_FORM_URLENCODED: @@ -139,7 +127,7 @@ QString getCType(RequestFormat format, QString plainType) { return plainType; } -QList> getHeaders(QJsonObject h, QString imageFormat, QMap types, RequestFormat format) { +QList> getHeaders(QJsonObject h, QString imageFormat, RequestFormat format) { QList> headers; for (QString s : h.keys()) { if (s.toLower() == "content-type") continue; @@ -149,20 +137,10 @@ QList> getHeaders(QJsonObject h, QString imageFormat, QM else headers << QPair(s, v.toString()); } - headers << QPair("Content-Type", getCType(format, types.value(imageFormat))); + headers << QPair("Content-Type", getCType(format, normalFormatMIME(normalFormatFromName(imageFormat)))); return headers; } -QString CustomUploader::getFormatString(bool animated) { - if (iFormat == "base64") - return animated ? "GIF" : "PNG"; - else if (QRegExp("[^+]+\\+[^+]+").exactMatch(iFormat)) - return iFormat.split('+')[(int)animated]; - else if (QRegExp("base64\\([^+]+\\+[^+]+)").exactMatch(iFormat)) - return iFormat.mid(7, iFormat.length() - 8).split('+')[(int)animated]; - return ""; -} - QJsonObject recurseAndReplace(QJsonObject &body, QByteArray &data, QString contentType) { QJsonObject o; for (QString s : body.keys()) { @@ -234,25 +212,26 @@ void parseResult(QJsonDocument result, QByteArray data, QString returnPathspec, } } -void CustomUploader::doUpload(QByteArray imgData) { - auto h = getHeaders(headers, getFormatString(false), types, this->rFormat); - QString format = getFormatString(false); // Soon:tm: +void CustomUploader::doUpload(QByteArray imgData, QString format) { + auto h = getHeaders(headers, format, this->rFormat); QByteArray data; - if (iFormat == "base64" || QRegExp("base64\\([^+]\\+[^+]\\)").exactMatch(iFormat)) imgData = imgData.toBase64(); + if (base64) imgData = imgData.toBase64(); switch (this->rFormat) { case RequestFormat::PLAIN: { data = imgData; } break; case RequestFormat::JSON: { if (body.isString()) { - QStringList split = body.toString().replace("%contenttype", types.value(format)).split("%imagedata"); + QStringList split = body.toString().replace("%contenttype", normalFormatMIME(normalFormatFromName(format))).split("%imagedata"); for (int i = 0; i < split.size(); i++) { data.append(split[i]); if (i < split.size() - 1) data.append(imgData); } } else { QJsonObject vo = body.toObject(); - data = QJsonDocument::fromVariant(recurseAndReplace(vo, imgData, types.value(format)).toVariantMap()).toJson(); + data = QJsonDocument::fromVariant( + recurseAndReplace(vo, imgData, normalFormatMIME(normalFormatFromName(format))).toVariantMap()) + .toJson(); } } break; case RequestFormat::X_WWW_FORM_URLENCODED: { @@ -264,7 +243,8 @@ void CustomUploader::doUpload(QByteArray imgData) { QByteArray strB; if (str.startsWith("/") && str.endsWith("/")) { str = str.mid(1, str.length() - 2); - QStringList split = str.replace("%contenttype", types.value(format)).split("%imagedata"); + QStringList split + = str.replace("%contenttype", normalFormatMIME(normalFormatFromName(format))).split("%imagedata"); for (int i = 0; i < split.size(); i++) { strB.append(split[i]); if (i < split.size() - 1) strB.append(imgData); diff --git a/uploaders/customuploader.hpp b/uploaders/customuploader.hpp index 6e65f9e..bb557b0 100644 --- a/uploaders/customuploader.hpp +++ b/uploaders/customuploader.hpp @@ -15,10 +15,7 @@ public: CustomUploader(QString absFilePath); QString name(); QString description(); - std::tuple format(); - void doUpload(QByteArray imgData); - QString getFormatString(bool animated); - QMap types; + void doUpload(QByteArray imgData, QString format); private: double limit = -1; @@ -29,8 +26,8 @@ private: QUrl target; QJsonValue body; QJsonObject headers; + bool base64 = false; QString returnPathspec; - QString iFormat; }; #endif // CUSTOMUPLOADER_HPP diff --git a/uploaders/default/clipboarduploader.cpp b/uploaders/default/clipboarduploader.cpp index 20bb17e..c5e3723 100644 --- a/uploaders/default/clipboarduploader.cpp +++ b/uploaders/default/clipboarduploader.cpp @@ -2,9 +2,17 @@ #include #include +#include +#include #include -void ClipboardUploader::doUpload(QByteArray imgData) { - QApplication::clipboard()->setImage(QImage::fromData(imgData, std::get<0>(format()).toLocal8Bit().constData())); +void ClipboardUploader::doUpload(QByteArray imgData, QString format) { + auto f = formats::recordingFormatFromName(format); + if (f != formats::Recording::None) { + auto data = new QMimeData(); + data->setData(formats::recordingFormatMIME(f), imgData); + QApplication::clipboard()->setMimeData(data); + } + QApplication::clipboard()->setImage(QImage::fromData(imgData, format.toLocal8Bit().constData())); notifications::notify("KShare", "Copied to clipboard!"); } diff --git a/uploaders/default/clipboarduploader.hpp b/uploaders/default/clipboarduploader.hpp index c157230..5794386 100644 --- a/uploaders/default/clipboarduploader.hpp +++ b/uploaders/default/clipboarduploader.hpp @@ -12,11 +12,8 @@ public: QString description() { return "Copies the image to clipboard"; } - std::tuple format() { - return std::tuple("PNG", "MP4"); - } - void doUpload(QByteArray imgData); + void doUpload(QByteArray imgData, QString format); }; #endif // CLIPBOARDUPLOADER_HPP diff --git a/uploaders/default/imguruploader.cpp b/uploaders/default/imguruploader.cpp index 98071de..108e8f2 100644 --- a/uploaders/default/imguruploader.cpp +++ b/uploaders/default/imguruploader.cpp @@ -7,7 +7,7 @@ #include #include -void ImgurUploader::doUpload(QByteArray byteArray) { +void ImgurUploader::doUpload(QByteArray byteArray, QString) { if (byteArray.size() > 1e+7) { notifications::notify("KShare imgur Uploader ", "Failed upload! Image too big"); return; diff --git a/uploaders/default/imguruploader.hpp b/uploaders/default/imguruploader.hpp index ec13a09..9ce9e99 100644 --- a/uploaders/default/imguruploader.hpp +++ b/uploaders/default/imguruploader.hpp @@ -11,10 +11,7 @@ public: QString description() { return "imgur.com uploader"; } - std::tuple format() { - return std::tuple("PNG", "MP4"); - } - void doUpload(QByteArray byteArray); + void doUpload(QByteArray byteArray, QString); }; #endif // IMGURUPLOADER_HPP diff --git a/uploaders/uploader.hpp b/uploaders/uploader.hpp index 5509d3f..5bfaca3 100644 --- a/uploaders/uploader.hpp +++ b/uploaders/uploader.hpp @@ -6,10 +6,9 @@ class Uploader { public: - virtual void doUpload(QByteArray imgData) = 0; + virtual void doUpload(QByteArray imgData, QString format) = 0; virtual QString name() = 0; virtual QString description() = 0; - virtual std::tuple format() = 0; }; #endif // UPLOADER_HPP diff --git a/uploaders/uploadersingleton.cpp b/uploaders/uploadersingleton.cpp index be2026b..b929db1 100644 --- a/uploaders/uploadersingleton.cpp +++ b/uploaders/uploadersingleton.cpp @@ -5,8 +5,11 @@ #include #include #include +#include #include +#include #include +#include #include UploaderSingleton::UploaderSingleton() @@ -57,29 +60,29 @@ void UploaderSingleton::registerUploader(Uploader *uploader) { void UploaderSingleton::upload(QPixmap *pixmap) { auto u = uploaders.value(uploader); - QByteArray arr; - QBuffer data(&arr); - pixmap->save(&data, std::get<0>(u->format()).toLocal8Bit().constData()); - u->doUpload(arr); - data.close(); + QString format = settings::settings().value("captureformat", "PNG").toString(); + QFile file(saveDir.absoluteFilePath(formatter::format(settings::settings().value("fileFormat").toString(), format.toLower()))); + + if (file.open(QFile::ReadWrite)) { + pixmap->save(&file, format.toLocal8Bit().constData()); + file.seek(0); + u->doUpload(file.readAll(), format); + } else + notifications::notify("KShare - Failed to save picture", file.errorString(), QSystemTrayIcon::Warning); delete pixmap; } -void UploaderSingleton::upload(QByteArray img) { - uploaders.value(uploader)->doUpload(img); +void UploaderSingleton::upload(QByteArray img, QString format) { + uploaders.value(uploader)->doUpload(img, format); } -void UploaderSingleton::upload(QFile img) { +void UploaderSingleton::upload(QFile img, QString format) { if (img.open(QIODevice::ReadOnly)) { - uploaders.value(uploader)->doUpload(img.readAll()); + uploaders.value(uploader)->doUpload(img.readAll(), format); img.close(); } } -std::tuple UploaderSingleton::format() { - return uploaders.value(uploader)->format(); -} - QList UploaderSingleton::uploaderList() { return uploaders.values(); } diff --git a/uploaders/uploadersingleton.hpp b/uploaders/uploadersingleton.hpp index a16b918..95b84e1 100644 --- a/uploaders/uploadersingleton.hpp +++ b/uploaders/uploadersingleton.hpp @@ -14,9 +14,8 @@ public: } void registerUploader(Uploader *uploader); void upload(QPixmap *pixmap); - void upload(QByteArray img); - void upload(QFile img); - virtual std::tuple format(); + void upload(QByteArray img, QString format); + void upload(QFile img, QString format); QList uploaderList(); void set(QString uploader); QString selectedUploader();