simplified Image
This commit is contained in:
@@ -37,29 +37,4 @@ using EmoteIdMap = std::unordered_map<EmoteId, EmotePtr>;
|
||||
using WeakEmoteMap = std::unordered_map<EmoteName, std::weak_ptr<const Emote>>;
|
||||
using WeakEmoteIdMap = std::unordered_map<EmoteId, std::weak_ptr<const Emote>>;
|
||||
|
||||
// struct EmoteData2 {
|
||||
// EmoteName name;
|
||||
// ImageSet images;
|
||||
// Tooltip tooltip;
|
||||
// Url homePage;
|
||||
//};
|
||||
//
|
||||
// class Emote
|
||||
//{
|
||||
// public:
|
||||
// Emote(EmoteData2 &&data);
|
||||
// Emote(const EmoteData2 &data);
|
||||
//
|
||||
// const Url &getHomePage() const;
|
||||
// const EmoteName &getName() const;
|
||||
// const Tooltip &getTooltip() const;
|
||||
// const ImageSet &getImages() const;
|
||||
// const QString &getCopyString() const;
|
||||
// bool operator==(const Emote &other) const;
|
||||
// bool operator!=(const Emote &other) const;
|
||||
//
|
||||
// private:
|
||||
// EmoteData2 data_;
|
||||
//};
|
||||
|
||||
} // namespace chatterino
|
||||
|
||||
+42
-95
@@ -21,22 +21,14 @@
|
||||
|
||||
namespace chatterino {
|
||||
namespace {
|
||||
const QPixmap *getPixmap(const Pixmap &pixmap)
|
||||
{
|
||||
if (pixmap.which() == 0)
|
||||
return boost::get<const QPixmap *>(pixmap);
|
||||
else
|
||||
return boost::get<std::unique_ptr<QPixmap>>(pixmap).get();
|
||||
}
|
||||
|
||||
// Frames
|
||||
Frames::Frames()
|
||||
{
|
||||
DebugCount::increase("images");
|
||||
}
|
||||
|
||||
Frames::Frames(std::vector<Frame> &&frames)
|
||||
: items_(std::move(frames))
|
||||
Frames::Frames(const QVector<Frame<QPixmap>> &frames)
|
||||
: items_(frames)
|
||||
{
|
||||
DebugCount::increase("images");
|
||||
if (this->animated()) DebugCount::increase("animated images");
|
||||
@@ -68,22 +60,22 @@ bool Frames::animated() const
|
||||
return this->items_.size() > 1;
|
||||
}
|
||||
|
||||
const QPixmap *Frames::current() const
|
||||
boost::optional<QPixmap> Frames::current() const
|
||||
{
|
||||
if (this->items_.size() == 0) return nullptr;
|
||||
return getPixmap(this->items_[this->index_].pixmap);
|
||||
if (this->items_.size() == 0) return boost::none;
|
||||
return this->items_[this->index_].image;
|
||||
}
|
||||
|
||||
const QPixmap *Frames::first() const
|
||||
boost::optional<QPixmap> Frames::first() const
|
||||
{
|
||||
if (this->items_.size() == 0) return nullptr;
|
||||
return getPixmap(this->items_.front().pixmap);
|
||||
if (this->items_.size() == 0) return boost::none;
|
||||
return this->items_.front().image;
|
||||
}
|
||||
|
||||
// functions
|
||||
std::vector<ParseFrame> readFrames(QImageReader &reader, const Url &url)
|
||||
QVector<Frame<QImage>> readFrames(QImageReader &reader, const Url &url)
|
||||
{
|
||||
std::vector<ParseFrame> frames;
|
||||
QVector<Frame<QImage>> frames;
|
||||
|
||||
if (reader.imageCount() == 0) {
|
||||
Log("Error while reading image {}: '{}'", url.string,
|
||||
@@ -97,7 +89,7 @@ std::vector<ParseFrame> readFrames(QImageReader &reader, const Url &url)
|
||||
QPixmap::fromImage(image);
|
||||
|
||||
int duration = std::max(20, reader.nextImageDelay());
|
||||
frames.push_back(ParseFrame{image, duration});
|
||||
frames.push_back(Frame<QImage>{image, duration});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -109,36 +101,22 @@ std::vector<ParseFrame> readFrames(QImageReader &reader, const Url &url)
|
||||
return frames;
|
||||
}
|
||||
|
||||
void queueLoadedEvent()
|
||||
{
|
||||
static auto eventQueued = false;
|
||||
|
||||
if (!eventQueued) {
|
||||
eventQueued = true;
|
||||
|
||||
QTimer::singleShot(250, [] {
|
||||
getApp()->windows->incGeneration();
|
||||
getApp()->windows->layoutChannelViews();
|
||||
eventQueued = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// parsed
|
||||
template <typename Assign>
|
||||
void asd(std::queue<std::pair<Assign, std::vector<Frame>>> &queued,
|
||||
std::mutex &mutex, std::atomic_bool &loadedEventQueued)
|
||||
void assignDelayed(
|
||||
std::queue<std::pair<Assign, QVector<Frame<QPixmap>>>> &queued,
|
||||
std::mutex &mutex, std::atomic_bool &loadedEventQueued)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
int i = 0;
|
||||
|
||||
while (!queued.empty()) {
|
||||
queued.front().first(std::move(queued.front().second));
|
||||
queued.front().first(queued.front().second);
|
||||
queued.pop();
|
||||
|
||||
if (++i > 50) {
|
||||
QTimer::singleShot(3,
|
||||
[&] { asd(queued, mutex, loadedEventQueued); });
|
||||
QTimer::singleShot(
|
||||
3, [&] { assignDelayed(queued, mutex, loadedEventQueued); });
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -148,34 +126,31 @@ void asd(std::queue<std::pair<Assign, std::vector<Frame>>> &queued,
|
||||
}
|
||||
|
||||
template <typename Assign>
|
||||
auto makeConvertCallback(std::vector<ParseFrame> parsed, Assign assign)
|
||||
auto makeConvertCallback(const QVector<Frame<QImage>> &parsed, Assign assign)
|
||||
{
|
||||
return [parsed = std::move(parsed), assign] {
|
||||
// BenchmarkGuard guard("convert image");
|
||||
|
||||
return [parsed, assign] {
|
||||
// convert to pixmap
|
||||
auto frames = std::vector<Frame>();
|
||||
auto frames = QVector<Frame<QPixmap>>();
|
||||
std::transform(parsed.begin(), parsed.end(), std::back_inserter(frames),
|
||||
[](auto &frame) {
|
||||
return Frame{std::make_unique<QPixmap>(
|
||||
QPixmap::fromImage(frame.image)),
|
||||
frame.duration};
|
||||
return Frame<QPixmap>{
|
||||
QPixmap::fromImage(frame.image), frame.duration};
|
||||
});
|
||||
|
||||
// put into stack
|
||||
static std::queue<std::pair<Assign, std::vector<Frame>>> queued;
|
||||
static std::queue<std::pair<Assign, QVector<Frame<QPixmap>>>> queued;
|
||||
static std::mutex mutex;
|
||||
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
queued.emplace(assign, std::move(frames));
|
||||
queued.emplace(assign, frames);
|
||||
|
||||
static std::atomic_bool loadedEventQueued{false};
|
||||
|
||||
if (!loadedEventQueued) {
|
||||
loadedEventQueued = true;
|
||||
|
||||
QTimer::singleShot(100,
|
||||
[=] { asd(queued, mutex, loadedEventQueued); });
|
||||
QTimer::singleShot(
|
||||
100, [=] { assignDelayed(queued, mutex, loadedEventQueued); });
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -200,12 +175,7 @@ ImagePtr Image::fromUrl(const Url &url, qreal scale)
|
||||
return shared;
|
||||
}
|
||||
|
||||
ImagePtr Image::fromOwningPixmap(std::unique_ptr<QPixmap> pixmap, qreal scale)
|
||||
{
|
||||
return ImagePtr(new Image(std::move(pixmap), scale));
|
||||
}
|
||||
|
||||
ImagePtr Image::fromNonOwningPixmap(QPixmap *pixmap, qreal scale)
|
||||
ImagePtr Image::fromPixmap(const QPixmap &pixmap, qreal scale)
|
||||
{
|
||||
return ImagePtr(new Image(pixmap, scale));
|
||||
}
|
||||
@@ -228,20 +198,10 @@ Image::Image(const Url &url, qreal scale)
|
||||
{
|
||||
}
|
||||
|
||||
Image::Image(std::unique_ptr<QPixmap> owning, qreal scale)
|
||||
Image::Image(const QPixmap &pixmap, qreal scale)
|
||||
: scale_(scale)
|
||||
, frames_(QVector<Frame<QPixmap>>{Frame<QPixmap>{pixmap}})
|
||||
{
|
||||
std::vector<Frame> vec;
|
||||
vec.push_back(Frame{std::move(owning)});
|
||||
this->frames_ = std::move(vec);
|
||||
}
|
||||
|
||||
Image::Image(QPixmap *nonOwning, qreal scale)
|
||||
: scale_(scale)
|
||||
{
|
||||
std::vector<Frame> vec;
|
||||
vec.push_back(Frame{nonOwning});
|
||||
this->frames_ = std::move(vec);
|
||||
}
|
||||
|
||||
const Url &Image::url() const
|
||||
@@ -249,7 +209,7 @@ const Url &Image::url() const
|
||||
return this->url_;
|
||||
}
|
||||
|
||||
const QPixmap *Image::pixmap() const
|
||||
boost::optional<QPixmap> Image::pixmap() const
|
||||
{
|
||||
assertInGuiThread();
|
||||
|
||||
@@ -266,7 +226,7 @@ qreal Image::scale() const
|
||||
return this->scale_;
|
||||
}
|
||||
|
||||
bool Image::empty() const
|
||||
bool Image::isEmpty() const
|
||||
{
|
||||
return this->empty_;
|
||||
}
|
||||
@@ -301,37 +261,24 @@ int Image::height() const
|
||||
void Image::load()
|
||||
{
|
||||
NetworkRequest req(this->url().string);
|
||||
req.setExecuteConcurrently(true);
|
||||
req.setCaller(&this->object_);
|
||||
req.setUseQuickLoadCache(true);
|
||||
req.onSuccess([that = this, weak = weakOf(this)](auto result) -> Outcome {
|
||||
assertInGuiThread();
|
||||
|
||||
auto shared = weak.lock();
|
||||
if (!shared) return Failure;
|
||||
|
||||
static auto parseThread = [] {
|
||||
auto thread = std::make_unique<QThread>();
|
||||
thread->start();
|
||||
return thread;
|
||||
}();
|
||||
auto data = result.getData();
|
||||
|
||||
postToThread(
|
||||
[data = result.getData(), weak, that] {
|
||||
// BenchmarkGuard guard("parse image");
|
||||
// const cast since we are only reading from it
|
||||
QBuffer buffer(const_cast<QByteArray *>(&data));
|
||||
buffer.open(QIODevice::ReadOnly);
|
||||
QImageReader reader(&buffer);
|
||||
auto parsed = readFrames(reader, that->url());
|
||||
|
||||
// const cast since we are only reading from it
|
||||
QBuffer buffer(const_cast<QByteArray *>(&data));
|
||||
buffer.open(QIODevice::ReadOnly);
|
||||
QImageReader reader(&buffer);
|
||||
auto parsed = readFrames(reader, that->url());
|
||||
|
||||
postToThread(
|
||||
makeConvertCallback(std::move(parsed), [weak](auto frames) {
|
||||
if (auto shared = weak.lock())
|
||||
shared->frames_ = std::move(frames);
|
||||
}));
|
||||
},
|
||||
parseThread.get());
|
||||
postToThread(makeConvertCallback(parsed, [weak](auto frames) {
|
||||
if (auto shared = weak.lock()) shared->frames_ = frames;
|
||||
}));
|
||||
|
||||
return Success;
|
||||
});
|
||||
@@ -341,7 +288,7 @@ void Image::load()
|
||||
|
||||
bool Image::operator==(const Image &other) const
|
||||
{
|
||||
if (this->empty() && other.empty()) return true;
|
||||
if (this->isEmpty() && other.isEmpty()) return true;
|
||||
if (!this->url_.string.isEmpty() && this->url_ == other.url_) return true;
|
||||
if (this->frames_.first() == other.frames_.first()) return true;
|
||||
|
||||
|
||||
+11
-17
@@ -5,6 +5,7 @@
|
||||
#include <QPixmap>
|
||||
#include <QString>
|
||||
#include <QThread>
|
||||
#include <QVector>
|
||||
#include <atomic>
|
||||
#include <boost/noncopyable.hpp>
|
||||
#include <boost/variant.hpp>
|
||||
@@ -15,31 +16,27 @@
|
||||
|
||||
namespace chatterino {
|
||||
namespace {
|
||||
using Pixmap = boost::variant<const QPixmap *, std::unique_ptr<QPixmap>>;
|
||||
template <typename Image>
|
||||
struct Frame {
|
||||
Pixmap pixmap;
|
||||
int duration;
|
||||
};
|
||||
struct ParseFrame {
|
||||
QImage image;
|
||||
Image image;
|
||||
int duration;
|
||||
};
|
||||
class Frames
|
||||
{
|
||||
public:
|
||||
Frames();
|
||||
Frames(std::vector<Frame> &&frames);
|
||||
Frames(const QVector<Frame<QPixmap>> &frames);
|
||||
~Frames();
|
||||
Frames(Frames &&other) = default;
|
||||
Frames &operator=(Frames &&other) = default;
|
||||
|
||||
bool animated() const;
|
||||
void advance();
|
||||
const QPixmap *current() const;
|
||||
const QPixmap *first() const;
|
||||
boost::optional<QPixmap> current() const;
|
||||
boost::optional<QPixmap> first() const;
|
||||
|
||||
private:
|
||||
std::vector<Frame> items_;
|
||||
QVector<Frame<QPixmap>> items_;
|
||||
int index_{0};
|
||||
int durationOffset_{0};
|
||||
};
|
||||
@@ -52,15 +49,13 @@ class Image : public std::enable_shared_from_this<Image>, boost::noncopyable
|
||||
{
|
||||
public:
|
||||
static ImagePtr fromUrl(const Url &url, qreal scale = 1);
|
||||
static ImagePtr fromOwningPixmap(std::unique_ptr<QPixmap> pixmap,
|
||||
qreal scale = 1);
|
||||
static ImagePtr fromNonOwningPixmap(QPixmap *pixmap, qreal scale = 1);
|
||||
static ImagePtr fromPixmap(const QPixmap &pixmap, qreal scale = 1);
|
||||
static ImagePtr getEmpty();
|
||||
|
||||
const Url &url() const;
|
||||
const QPixmap *pixmap() const;
|
||||
boost::optional<QPixmap> pixmap() const;
|
||||
qreal scale() const;
|
||||
bool empty() const;
|
||||
bool isEmpty() const;
|
||||
int width() const;
|
||||
int height() const;
|
||||
bool animated() const;
|
||||
@@ -71,8 +66,7 @@ public:
|
||||
private:
|
||||
Image();
|
||||
Image(const Url &url, qreal scale);
|
||||
Image(std::unique_ptr<QPixmap> owning, qreal scale);
|
||||
Image(QPixmap *nonOwning, qreal scale);
|
||||
Image(const QPixmap &nonOwning, qreal scale);
|
||||
|
||||
void load();
|
||||
|
||||
|
||||
@@ -71,11 +71,11 @@ const ImagePtr &ImageSet::getImage(float scale) const
|
||||
scale = 1;
|
||||
}
|
||||
|
||||
if (!this->imageX3_->empty() && quality == 3) {
|
||||
if (!this->imageX3_->isEmpty() && quality == 3) {
|
||||
return this->imageX3_;
|
||||
}
|
||||
|
||||
if (!this->imageX2_->empty() && quality == 2) {
|
||||
if (!this->imageX2_->isEmpty() && quality == 2) {
|
||||
return this->imageX3_;
|
||||
}
|
||||
|
||||
|
||||
@@ -21,8 +21,6 @@ public:
|
||||
|
||||
const ImagePtr &getImage(float scale) const;
|
||||
|
||||
ImagePtr getImage(float scale);
|
||||
|
||||
bool operator==(const ImageSet &other) const;
|
||||
bool operator!=(const ImageSet &other) const;
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#include "messages/MessageElement.hpp"
|
||||
|
||||
#include "Application.hpp"
|
||||
#include "common/Emotemap.hpp"
|
||||
#include "controllers/moderationactions/ModerationActions.hpp"
|
||||
#include "debug/Benchmark.hpp"
|
||||
#include "messages/layouts/MessageLayoutContainer.hpp"
|
||||
@@ -102,7 +101,7 @@ void EmoteElement::addToContainer(MessageLayoutContainer &container,
|
||||
if (flags.hasAny(this->getFlags())) {
|
||||
if (flags.has(MessageElementFlag::EmoteImages)) {
|
||||
auto image = this->emote_->images.getImage(container.getScale());
|
||||
if (image->empty()) return;
|
||||
if (image->isEmpty()) return;
|
||||
|
||||
auto size = QSize(int(container.getScale() * image->width()),
|
||||
int(container.getScale() * image->height()));
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include "common/Emotemap.hpp"
|
||||
#include "common/FlagsEnum.hpp"
|
||||
#include "messages/Emote.hpp"
|
||||
#include "messages/Image.hpp"
|
||||
|
||||
Reference in New Issue
Block a user