From af562cb4cad52b55985c9f13e3fc8927a87e6b12 Mon Sep 17 00:00:00 2001 From: thunder2 Date: Wed, 26 Apr 2023 21:53:59 +0200 Subject: [PATCH] FeedReader: Added shrink of images for board post --- plugins/FeedReader/gui/AddFeedDialog.cpp | 7 ++ plugins/FeedReader/gui/AddFeedDialog.ui | 10 +- plugins/FeedReader/gui/FeedReaderDialog.cpp | 33 ++++++ plugins/FeedReader/gui/FeedReaderDialog.h | 1 + plugins/FeedReader/gui/FeedReaderNotify.cpp | 5 + plugins/FeedReader/gui/FeedReaderNotify.h | 2 + plugins/FeedReader/interface/rsFeedReader.h | 27 +++++ plugins/FeedReader/lang/FeedReader_en.ts | 21 ++-- plugins/FeedReader/services/p3FeedReader.cc | 110 +++++++++++++++++- plugins/FeedReader/services/p3FeedReader.h | 8 ++ .../FeedReader/services/rsFeedReaderItems.h | 1 + .../src/gui/Posted/PostedCreatePostDialog.cpp | 12 +- .../src/gui/Posted/PostedCreatePostDialog.h | 3 +- 13 files changed, 226 insertions(+), 14 deletions(-) diff --git a/plugins/FeedReader/gui/AddFeedDialog.cpp b/plugins/FeedReader/gui/AddFeedDialog.cpp index 588428a8d..4e0645607 100644 --- a/plugins/FeedReader/gui/AddFeedDialog.cpp +++ b/plugins/FeedReader/gui/AddFeedDialog.cpp @@ -99,6 +99,8 @@ AddFeedDialog::AddFeedDialog(RsFeedReader *feedReader, FeedReaderNotify *notify, ui->postedFirstImageCheckBox->setChecked(false); ui->postedOnlyImageCheckBox->setEnabled(false); ui->postedOnlyImageCheckBox->setChecked(false); + ui->postedShinkImageCheckBox->setEnabled(false); + ui->postedShinkImageCheckBox->setChecked(false); ui->useAuthenticationCheckBox->setChecked(false); ui->useStandardStorageTimeCheckBox->setChecked(true); ui->useStandardUpdateInterval->setChecked(true); @@ -197,9 +199,11 @@ void AddFeedDialog::postedFirstImageToggled() { bool checked = ui->postedFirstImageCheckBox->isChecked(); ui->postedOnlyImageCheckBox->setEnabled(checked); + ui->postedShinkImageCheckBox->setEnabled(checked); if (!checked) { ui->postedOnlyImageCheckBox->setChecked(false); + ui->postedShinkImageCheckBox->setChecked(false); } } @@ -209,6 +213,7 @@ void AddFeedDialog::typePostedToggled() mStateHelper->setWidgetEnabled(ui->postedComboBox, checked); ui->updatePostedInfoCheckBox->setEnabled(checked); ui->postedFirstImageCheckBox->setEnabled(checked); + ui->postedShinkImageCheckBox->setEnabled(checked); if (checked) { ui->typeLocalCheckBox->setChecked(false); @@ -301,6 +306,7 @@ bool AddFeedDialog::fillFeed(uint32_t feedId) ui->updatePostedInfoCheckBox->setChecked(feedInfo.flag.updatePostedInfo); ui->postedFirstImageCheckBox->setChecked(feedInfo.flag.postedFirstImage); ui->postedOnlyImageCheckBox->setChecked(feedInfo.flag.postedOnlyImage); + ui->postedShinkImageCheckBox->setChecked(feedInfo.flag.postedShrinkImage); ui->activatedCheckBox->setChecked(!feedInfo.flag.deactivated); ui->embedImagesCheckBox->setChecked(feedInfo.flag.embedImages); ui->saveCompletePageCheckBox->setChecked(feedInfo.flag.saveCompletePage); @@ -397,6 +403,7 @@ void AddFeedDialog::getFeedInfo(FeedInfo &feedInfo) feedInfo.flag.updatePostedInfo = ui->updatePostedInfoCheckBox->isChecked() && ui->updatePostedInfoCheckBox->isEnabled(); feedInfo.flag.postedFirstImage = ui->postedFirstImageCheckBox->isChecked() && ui->postedFirstImageCheckBox->isEnabled(); feedInfo.flag.postedOnlyImage = ui->postedOnlyImageCheckBox->isChecked() && ui->postedOnlyImageCheckBox->isEnabled(); + feedInfo.flag.postedShrinkImage = ui->postedShinkImageCheckBox->isChecked() && ui->postedShinkImageCheckBox->isEnabled(); feedInfo.flag.deactivated = !ui->activatedCheckBox->isChecked(); feedInfo.flag.embedImages = ui->embedImagesCheckBox->isChecked(); feedInfo.flag.saveCompletePage = ui->saveCompletePageCheckBox->isChecked(); diff --git a/plugins/FeedReader/gui/AddFeedDialog.ui b/plugins/FeedReader/gui/AddFeedDialog.ui index f3bcaf85f..40b9bd46d 100644 --- a/plugins/FeedReader/gui/AddFeedDialog.ui +++ b/plugins/FeedReader/gui/AddFeedDialog.ui @@ -130,6 +130,13 @@ + + + + Shrink image + + + @@ -482,8 +489,9 @@ typePostedCheckBox postedComboBox updatePostedInfoCheckBox + postedShinkImageCheckBox postedFirstImageCheckBox - checkBox + postedOnlyImageCheckBox typeLocalCheckBox activatedCheckBox useInfoFromFeedCheckBox diff --git a/plugins/FeedReader/gui/FeedReaderDialog.cpp b/plugins/FeedReader/gui/FeedReaderDialog.cpp index 1c3d6ca8c..7ea17983b 100644 --- a/plugins/FeedReader/gui/FeedReaderDialog.cpp +++ b/plugins/FeedReader/gui/FeedReaderDialog.cpp @@ -35,6 +35,7 @@ #include "gui/settings/rsharesettings.h" #include "gui/notifyqt.h" #include "FeedReaderUserNotify.h" +#include "gui/Posted/PostedCreatePostDialog.h" #include "interface/rsFeedReader.h" #include "retroshare/rsiface.h" @@ -66,6 +67,7 @@ FeedReaderDialog::FeedReaderDialog(RsFeedReader *feedReader, FeedReaderNotify *n mMessageWidget = NULL; connect(mNotify, &FeedReaderNotify::feedChanged, this, &FeedReaderDialog::feedChanged, Qt::QueuedConnection); + connect(mNotify, &FeedReaderNotify::shrinkImage, this, &FeedReaderDialog::shrinkImage, Qt::QueuedConnection); connect(NotifyQt::getInstance(), SIGNAL(settingsChanged()), this, SLOT(settingsChanged())); @@ -604,6 +606,37 @@ void FeedReaderDialog::feedChanged(uint32_t feedId, int type) calculateFeedItems(); } +void FeedReaderDialog::shrinkImage() +{ + while (true) { + FeedReaderShrinkImageTask *shrinkImageTask = mFeedReader->getShrinkImageTask(); + + if (!shrinkImageTask) { + return; + } + + switch (shrinkImageTask->mType) { + case FeedReaderShrinkImageTask::POSTED: + { + QImage image; + if (image.loadFromData(shrinkImageTask->mImage.data(), shrinkImageTask->mImage.size())) { + QByteArray imageBytes; + QImage imageOpt; + if (PostedCreatePostDialog::optimizeImage(image, imageBytes, imageOpt)) { + shrinkImageTask->mImageResult.assign(imageBytes.begin(), imageBytes.end()); + shrinkImageTask->mResult = true; + } + } + break; + } + default: + shrinkImageTask->mResult = false; + } + + mFeedReader->setShrinkImageTaskResult(shrinkImageTask); + } +} + FeedReaderMessageWidget *FeedReaderDialog::feedMessageWidget(uint32_t id) { int tabCount = ui->messageTabWidget->count(); diff --git a/plugins/FeedReader/gui/FeedReaderDialog.h b/plugins/FeedReader/gui/FeedReaderDialog.h index d684f1f4b..b4854d2f3 100644 --- a/plugins/FeedReader/gui/FeedReaderDialog.h +++ b/plugins/FeedReader/gui/FeedReaderDialog.h @@ -69,6 +69,7 @@ private slots: /* FeedReaderNotify */ void feedChanged(uint32_t feedId, int type); + void shrinkImage(); private: uint32_t currentFeedId(); diff --git a/plugins/FeedReader/gui/FeedReaderNotify.cpp b/plugins/FeedReader/gui/FeedReaderNotify.cpp index f2aa7ad1d..33b0c294a 100644 --- a/plugins/FeedReader/gui/FeedReaderNotify.cpp +++ b/plugins/FeedReader/gui/FeedReaderNotify.cpp @@ -33,3 +33,8 @@ void FeedReaderNotify::notifyMsgChanged(uint32_t feedId, const std::string &msgI { emit msgChanged(feedId, QString::fromStdString(msgId), type); } + +void FeedReaderNotify::notifyShrinkImage() +{ + emit shrinkImage(); +} diff --git a/plugins/FeedReader/gui/FeedReaderNotify.h b/plugins/FeedReader/gui/FeedReaderNotify.h index 5a8ad712a..18090e70c 100644 --- a/plugins/FeedReader/gui/FeedReaderNotify.h +++ b/plugins/FeedReader/gui/FeedReaderNotify.h @@ -34,10 +34,12 @@ public: /* RsFeedReaderNotify */ virtual void notifyFeedChanged(uint32_t feedId, int type); virtual void notifyMsgChanged(uint32_t feedId, const std::string &msgId, int type); + virtual void notifyShrinkImage(); signals: void feedChanged(uint32_t feedId, int type); void msgChanged(uint32_t feedId, const QString &msgId, int type); + void shrinkImage(); }; #endif diff --git a/plugins/FeedReader/interface/rsFeedReader.h b/plugins/FeedReader/interface/rsFeedReader.h index bfb239400..ad1ecec9a 100644 --- a/plugins/FeedReader/interface/rsFeedReader.h +++ b/plugins/FeedReader/interface/rsFeedReader.h @@ -157,6 +157,7 @@ public: bool updatePostedInfo : 1; bool postedFirstImage : 1; bool postedOnlyImage : 1; + bool postedShrinkImage : 1; bool embedImages : 1; bool saveCompletePage : 1; bool preview : 1; @@ -190,6 +191,28 @@ public: } flag; }; +class FeedReaderShrinkImageTask +{ +public: + enum Type { + POSTED + }; + +public: + Type mType; + std::vector mImage; + std::vector mImageResult; + bool mResult; + +public: + FeedReaderShrinkImageTask(Type type, const std::vector &image) + { + mType = type; + mImage = image; + mResult = false; + } +}; + class RsFeedReaderNotify { public: @@ -197,6 +220,7 @@ public: virtual void notifyFeedChanged(uint32_t /*feedId*/, int /*type*/) {} virtual void notifyMsgChanged(uint32_t /*feedId*/, const std::string &/*msgId*/, int /*type*/) {} + virtual void notifyShrinkImage() {} }; class RsFeedReader @@ -242,6 +266,9 @@ public: virtual bool getForumGroups(std::vector &groups, bool onlyOwn) = 0; virtual bool getPostedGroups(std::vector &groups, bool onlyOwn) = 0; + virtual FeedReaderShrinkImageTask *getShrinkImageTask() = 0; + virtual void setShrinkImageTaskResult(FeedReaderShrinkImageTask *shrinkImageTask) = 0; + virtual RsFeedReaderErrorState processXPath(const std::list &xpathsToUse, const std::list &xpathsToRemove, std::string &description, std::string &errorString) = 0; virtual RsFeedReaderErrorState processXslt(const std::string &xslt, std::string &description, std::string &errorString) = 0; }; diff --git a/plugins/FeedReader/lang/FeedReader_en.ts b/plugins/FeedReader/lang/FeedReader_en.ts index af6f9422f..93db4a686 100644 --- a/plugins/FeedReader/lang/FeedReader_en.ts +++ b/plugins/FeedReader/lang/FeedReader_en.ts @@ -28,6 +28,11 @@ Use first image as board image + + + Shrink image + + Authentication (not yet supported) @@ -119,7 +124,7 @@ - + Type @@ -134,7 +139,7 @@ - + Transformation @@ -164,12 +169,12 @@ - + Update forum information - + Save complete web page (experimental for local feeds) @@ -194,8 +199,8 @@ - - + + Edit feed @@ -312,7 +317,7 @@ - + Message Folders @@ -367,7 +372,7 @@ - + Add new folder diff --git a/plugins/FeedReader/services/p3FeedReader.cc b/plugins/FeedReader/services/p3FeedReader.cc index 7d6f44a1c..fbda4d9e1 100644 --- a/plugins/FeedReader/services/p3FeedReader.cc +++ b/plugins/FeedReader/services/p3FeedReader.cc @@ -45,7 +45,7 @@ RsFeedReader *rsFeedReader = NULL; p3FeedReader::p3FeedReader(RsPluginHandler* pgHandler, RsGxsForums *forums, RsPosted *posted) : RsPQIService(RS_SERVICE_TYPE_PLUGIN_FEEDREADER, 5, pgHandler), - mFeedReaderMtx("p3FeedReader"), mDownloadMutex("p3FeedReaderDownload"), mProcessMutex("p3FeedReaderProcess"), mPreviewMutex("p3FeedReaderPreview") + mFeedReaderMtx("p3FeedReader"), mDownloadMutex("p3FeedReaderDownload"), mProcessMutex("p3FeedReaderProcess"), mImageMutex("p3FeedReaderImage"), mPreviewMutex("p3FeedReaderPreview") { mNextFeedId = 1; mNextMsgId = 1; @@ -118,6 +118,7 @@ static void feedToInfo(const RsFeedReaderFeed *feed, FeedInfo &info) info.flag.updatePostedInfo = (feed->flag & RS_FEED_FLAG_UPDATE_POSTED_INFO); info.flag.postedFirstImage = (feed->flag & RS_FEED_FLAG_POSTED_FIRST_IMAGE); info.flag.postedOnlyImage = (feed->flag & RS_FEED_FLAG_POSTED_ONLY_IMAGE); + info.flag.postedShrinkImage = (feed->flag & RS_FEED_FLAG_POSTED_SHRINK_IMAGE); info.flag.embedImages = (feed->flag & RS_FEED_FLAG_EMBED_IMAGES); info.flag.saveCompletePage = (feed->flag & RS_FEED_FLAG_SAVE_COMPLETE_PAGE); @@ -217,6 +218,9 @@ static void infoToFeed(const FeedInfo &info, RsFeedReaderFeed *feed) if (info.flag.postedOnlyImage) { feed->flag |= RS_FEED_FLAG_POSTED_ONLY_IMAGE; } + if (info.flag.postedShrinkImage) { + feed->flag |= RS_FEED_FLAG_POSTED_SHRINK_IMAGE; + } } static void feedMsgToInfo(const RsFeedReaderMsg *msg, FeedMsgInfo &info) @@ -1445,10 +1449,21 @@ int p3FeedReader::tick() } } + // check images + bool imageToShrink = false; + { + RsStackMutex stack(mImageMutex); /******* LOCK STACK MUTEX *********/ + + imageToShrink = !mImages.empty(); + } + if (mNotify) { for (it = notifyIds.begin(); it != notifyIds.end(); ++it) { mNotify->notifyFeedChanged(*it, NOTIFY_TYPE_MOD); } + if (imageToShrink) { + mNotify->notifyShrinkImage(); + } } return 0; @@ -2188,7 +2203,15 @@ void p3FeedReader::onProcessSuccess_addMsgs(uint32_t feedId, std::list shrinkedImage; + if (shrinkImage(FeedReaderShrinkImageTask::POSTED, mi.postedFirstImage, shrinkedImage)) { + postedPost.mImage.copy(shrinkedImage.data(), shrinkedImage.size()); + } + } else { + postedPost.mImage.copy(mi.postedFirstImage.data(), mi.postedFirstImage.size()); + } if (feedFlag & RS_FEED_FLAG_POSTED_ONLY_IMAGE) { /* ignore description */ } else { @@ -2614,3 +2637,86 @@ bool p3FeedReader::getPostedGroups(std::vector &groups, bool only return true; } + +bool p3FeedReader::shrinkImage(FeedReaderShrinkImageTask::Type type, const std::vector &image, std::vector &resultImage) +{ + if (!mNotify) { + return false; + } + + FeedReaderShrinkImageTask *shrinkImageTask = new FeedReaderShrinkImageTask(type, image); + { + RsStackMutex stack(mImageMutex); /******* LOCK STACK MUTEX *********/ + + mImages.push_back(shrinkImageTask); + } + + /* Wait until task is complete */ + int nSeconds = 0; + while (true) { + if (mStopped) { + return false; + } + + rstime::rs_usleep(1000 * 1000); // 1 second + + if (++nSeconds >= 30) { + // timeout + std::list::iterator it = std::find(mImages.begin(), mImages.end(), shrinkImageTask); + if (it != mImages.end()) { + mImages.erase(it); + + delete(shrinkImageTask); + + return false; + } + + // not found in mImages? + } + + { + RsStackMutex stack(mImageMutex); /******* LOCK STACK MUTEX *********/ + + std::list::iterator it = std::find(mResultImages.begin(), mResultImages.end(), shrinkImageTask); + if (it != mResultImages.end()) { + mResultImages.erase(it); + + bool result = shrinkImageTask->mResult; + if (result) { + resultImage = shrinkImageTask->mImageResult; + } + + delete(shrinkImageTask); + + return result; + } + } + } + + return false; +} + +FeedReaderShrinkImageTask *p3FeedReader::getShrinkImageTask() +{ + RsStackMutex stack(mImageMutex); /******* LOCK STACK MUTEX *********/ + + if (mImages.empty()) { + return NULL; + } + + FeedReaderShrinkImageTask *imageResize = mImages.front(); + mImages.pop_front(); + + return imageResize; +} + +void p3FeedReader::setShrinkImageTaskResult(FeedReaderShrinkImageTask *shrinkImageTask) +{ + if (!shrinkImageTask) { + return; + } + + RsStackMutex stack(mImageMutex); /******* LOCK STACK MUTEX *********/ + + mResultImages.push_back(shrinkImageTask); +} diff --git a/plugins/FeedReader/services/p3FeedReader.h b/plugins/FeedReader/services/p3FeedReader.h index c69832506..edca9ee1e 100644 --- a/plugins/FeedReader/services/p3FeedReader.h +++ b/plugins/FeedReader/services/p3FeedReader.h @@ -80,6 +80,9 @@ public: virtual bool getForumGroups(std::vector &groups, bool onlyOwn); virtual bool getPostedGroups(std::vector &groups, bool onlyOwn); + virtual FeedReaderShrinkImageTask *getShrinkImageTask(); + virtual void setShrinkImageTaskResult(FeedReaderShrinkImageTask *shrinkedImageTask); + virtual RsFeedReaderErrorState processXPath(const std::list &xpathsToUse, const std::list &xpathsToRemove, std::string &description, std::string &errorString); virtual RsFeedReaderErrorState processXslt(const std::string &xslt, std::string &description, std::string &errorString); @@ -104,6 +107,7 @@ public: bool getPostedGroup(const RsGxsGroupId &groupId, RsPostedGroup &postedGroup); bool updatePostedGroup(const RsPostedGroup &postedGroup, const std::string &groupName, const std::string &groupDescription); bool waitForToken(RsGxsIfaceHelper *interface, uint32_t token); + bool shrinkImage(FeedReaderShrinkImageTask::Type type, const std::vector &image, std::vector &resultImage); protected: /****************** p3Config STUFF *******************/ @@ -145,6 +149,10 @@ private: RsMutex mProcessMutex; std::list mProcessFeeds; + RsMutex mImageMutex; + std::list mImages; + std::list mResultImages; + RsMutex mPreviewMutex; p3FeedReaderThread *mPreviewDownloadThread; p3FeedReaderThread *mPreviewProcessThread; diff --git a/plugins/FeedReader/services/rsFeedReaderItems.h b/plugins/FeedReader/services/rsFeedReaderItems.h index 39d604f46..3adafd55a 100644 --- a/plugins/FeedReader/services/rsFeedReaderItems.h +++ b/plugins/FeedReader/services/rsFeedReaderItems.h @@ -49,6 +49,7 @@ const uint8_t RS_PKT_SUBTYPE_FEEDREADER_MSG = 0x03; #define RS_FEED_FLAG_UPDATE_POSTED_INFO 0x1000 #define RS_FEED_FLAG_POSTED_FIRST_IMAGE 0x2000 #define RS_FEED_FLAG_POSTED_ONLY_IMAGE 0x4000 +#define RS_FEED_FLAG_POSTED_SHRINK_IMAGE 0x8000 class RsFeedReaderFeed : public RsItem { diff --git a/retroshare-gui/src/gui/Posted/PostedCreatePostDialog.cpp b/retroshare-gui/src/gui/Posted/PostedCreatePostDialog.cpp index f0bc99551..bfccd3fc7 100644 --- a/retroshare-gui/src/gui/Posted/PostedCreatePostDialog.cpp +++ b/retroshare-gui/src/gui/Posted/PostedCreatePostDialog.cpp @@ -50,6 +50,8 @@ #define IMG_ATTACH 0 #define IMG_PICTURE 1 +const int MAXMESSAGESIZE = 199000; + PostedCreatePostDialog::PostedCreatePostDialog(RsPosted *posted, const RsGxsGroupId& grpId, const RsGxsId& default_author, QWidget *parent): QDialog(parent, Qt::WindowSystemMenuHint | Qt::WindowTitleHint | Qt::WindowMinimizeButtonHint | Qt::WindowMaximizeButtonHint | Qt::WindowCloseButtonHint), mPosted(posted), mGrpId(grpId), @@ -226,7 +228,7 @@ void PostedCreatePostDialog::addPicture() } QImage opt; - if(ImageUtil::optimizeSizeBytes(imagebytes, image, opt,"JPG", 640*480, MAXMESSAGESIZE - 2000)) { //Leave space for other stuff + if (optimizeImage(image, imagebytes, opt)) { ui->imageLabel->setPixmap(QPixmap::fromImage(opt)); ui->stackedWidgetPicture->setCurrentIndex(IMG_PICTURE); ui->removeButton->show(); @@ -274,7 +276,7 @@ void PostedCreatePostDialog::pastePicture() image = (qvariant_cast(mimeData->imageData())); QImage opt; - if(ImageUtil::optimizeSizeBytes(imagebytes, image, opt,"JPG", 640*480, MAXMESSAGESIZE - 2000)) { //Leave space for other stuff + if (optimizeImage(image, imagebytes, opt)) { ui->imageLabel->setPixmap(QPixmap::fromImage(opt)); ui->stackedWidgetPicture->setCurrentIndex(IMG_PICTURE); ui->removeButton->show(); @@ -287,6 +289,12 @@ void PostedCreatePostDialog::pastePicture() } } +bool PostedCreatePostDialog::optimizeImage(const QImage &image, QByteArray &imagebytes, QImage &imageOpt) +{ + // Leave space for other stuff + return ImageUtil::optimizeSizeBytes(imagebytes, image, imageOpt, "JPG", 640*480, MAXMESSAGESIZE - 2000); +} + int PostedCreatePostDialog::viewMode() { if (ui->viewPostButton->isChecked()) { diff --git a/retroshare-gui/src/gui/Posted/PostedCreatePostDialog.h b/retroshare-gui/src/gui/Posted/PostedCreatePostDialog.h index e952f6be8..5ac2c2e7d 100644 --- a/retroshare-gui/src/gui/Posted/PostedCreatePostDialog.h +++ b/retroshare-gui/src/gui/Posted/PostedCreatePostDialog.h @@ -45,10 +45,11 @@ public: void setNotes(const QString& notes); void setLink(const QString& link); + static bool optimizeImage(const QImage &image, QByteArray &imagebytes, QImage &imageOpt); + private: QString imagefilename; QByteArray imagebytes; - const int MAXMESSAGESIZE = 199000; private slots: void createPost();