mirror of
https://github.com/celisej567/abaddon.git
synced 2026-09-06 20:15:19 +03:00
maybe slightly better image loading maybe hopefully
This commit is contained in:
@@ -88,25 +88,22 @@ void ChatMessageItemContainer::UpdateContent() {
|
||||
}
|
||||
}
|
||||
|
||||
void ChatMessageItemContainer::UpdateImage() {
|
||||
for (auto it = m_img_loadmap.cbegin(); it != m_img_loadmap.cend();) {
|
||||
auto buf = Abaddon::Get().GetImageManager().GetFromURLIfCached(it->first);
|
||||
if (buf) {
|
||||
int w, h;
|
||||
std::tie(w, h) = GetImageDimensions(it->second.second.Width, it->second.second.Height);
|
||||
it->second.first->property_pixbuf() = buf->scale_simple(w, h, Gdk::INTERP_BILINEAR);
|
||||
it = m_img_loadmap.erase(it);
|
||||
} else
|
||||
it++;
|
||||
void ChatMessageItemContainer::UpdateImage(std::string url, Glib::RefPtr<Gdk::Pixbuf> buf) {
|
||||
if (!buf) return;
|
||||
|
||||
if (m_embed_img != nullptr && m_embed_imgurl == url) {
|
||||
int w, h;
|
||||
m_embed_img->get_size_request(w, h);
|
||||
m_embed_img->property_pixbuf() = buf->scale_simple(w, h, Gdk::INTERP_BILINEAR);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_embed_img != nullptr) {
|
||||
auto buf = Abaddon::Get().GetImageManager().GetFromURLIfCached(m_embed_imgurl);
|
||||
if (buf) {
|
||||
int w, h;
|
||||
m_embed_img->get_size_request(w, h);
|
||||
m_embed_img->property_pixbuf() = buf->scale_simple(w, h, Gdk::INTERP_BILINEAR);
|
||||
}
|
||||
auto it = m_img_loadmap.find(url);
|
||||
if (it != m_img_loadmap.end()) {
|
||||
int w, h;
|
||||
GetImageDimensions(it->second.second.Width, it->second.second.Height, w, h);
|
||||
it->second.first->property_pixbuf() = buf->scale_simple(w, h, Gdk::INTERP_BILINEAR);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -270,9 +267,9 @@ Gtk::EventBox *ChatMessageItemContainer::CreateEmbedComponent(const Message *dat
|
||||
img->set_halign(Gtk::ALIGN_CENTER);
|
||||
int w, h;
|
||||
if (is_img)
|
||||
std::tie(w, h) = GetImageDimensions(embed.Image.Width, embed.Image.Height, 200, 150);
|
||||
GetImageDimensions(embed.Image.Width, embed.Image.Height, w, h, 200, 150);
|
||||
else
|
||||
std::tie(w, h) = GetImageDimensions(embed.Thumbnail.Width, embed.Thumbnail.Height, 200, 150);
|
||||
GetImageDimensions(embed.Thumbnail.Width, embed.Thumbnail.Height, w, h, 200, 150);
|
||||
img->set_size_request(w, h);
|
||||
main->pack_start(*img);
|
||||
m_embed_img = img;
|
||||
@@ -319,7 +316,7 @@ Gtk::EventBox *ChatMessageItemContainer::CreateEmbedComponent(const Message *dat
|
||||
|
||||
Gtk::Image *ChatMessageItemContainer::CreateImageComponent(const AttachmentData &data) {
|
||||
int w, h;
|
||||
std::tie(w, h) = GetImageDimensions(data.Width, data.Height);
|
||||
GetImageDimensions(data.Width, data.Height, w, h);
|
||||
|
||||
auto &im = Abaddon::Get().GetImageManager();
|
||||
Gtk::Image *widget = Gtk::manage(new Gtk::Image);
|
||||
@@ -350,22 +347,6 @@ Gtk::Box *ChatMessageItemContainer::CreateAttachmentComponent(const AttachmentDa
|
||||
return box;
|
||||
}
|
||||
|
||||
std::pair<int, int> ChatMessageItemContainer::GetImageDimensions(int width, int height, int clampw, int clamph) {
|
||||
const auto frac = static_cast<float>(width) / height;
|
||||
|
||||
if (width > clampw) {
|
||||
width = clampw;
|
||||
height = clampw / frac;
|
||||
}
|
||||
|
||||
if (height > clamph) {
|
||||
height = clamph;
|
||||
width = clamph * frac;
|
||||
}
|
||||
|
||||
return std::make_pair(static_cast<int>(width), static_cast<int>(height));
|
||||
}
|
||||
|
||||
void ChatMessageItemContainer::HandleImage(const AttachmentData &data, Gtk::Image *img, std::string url) {
|
||||
m_img_loadmap[url] = std::make_pair(img, data);
|
||||
// ask the chatwindow to call UpdateImage because dealing with lifetimes sucks
|
||||
|
||||
@@ -13,7 +13,7 @@ public:
|
||||
// attributes = edited, deleted
|
||||
void UpdateAttributes();
|
||||
void UpdateContent();
|
||||
void UpdateImage();
|
||||
void UpdateImage(std::string url, Glib::RefPtr<Gdk::Pixbuf> buf);
|
||||
|
||||
protected:
|
||||
bool EmitImageLoad(std::string url);
|
||||
@@ -24,7 +24,6 @@ protected:
|
||||
Gtk::Image *CreateImageComponent(const AttachmentData &data);
|
||||
Gtk::Box *CreateAttachmentComponent(const AttachmentData &data); // non-image attachments
|
||||
void HandleImage(const AttachmentData &data, Gtk::Image *img, std::string url);
|
||||
static std::pair<int, int> GetImageDimensions(int width, int height, int clampw = 400, int clamph = 300);
|
||||
|
||||
std::unordered_map<std::string, std::pair<Gtk::Image *, AttachmentData>> m_img_loadmap;
|
||||
|
||||
|
||||
@@ -210,11 +210,11 @@ void ChatWindow::ProcessNewMessage(Snowflake id, bool prepend) {
|
||||
});
|
||||
content->signal_image_load().connect([this, id](std::string url) {
|
||||
auto &mgr = Abaddon::Get().GetImageManager();
|
||||
mgr.LoadFromURL(url, [this, id](Glib::RefPtr<Gdk::Pixbuf> buf) {
|
||||
mgr.LoadFromURL(url, [this, id, url](Glib::RefPtr<Gdk::Pixbuf> buf) {
|
||||
if (m_id_to_widget.find(id) != m_id_to_widget.end()) {
|
||||
auto *x = dynamic_cast<ChatMessageItemContainer *>(m_id_to_widget.at(id));
|
||||
if (x != nullptr)
|
||||
x->UpdateImage();
|
||||
x->UpdateImage(url, buf);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -23,23 +23,14 @@ std::string Cache::SanitizeString(std::string str) {
|
||||
}
|
||||
|
||||
void Cache::RespondFromPath(std::filesystem::path path, callback_type cb) {
|
||||
/*if (!std::filesystem::exists(path)) return;
|
||||
FILE *fp = std::fopen(path.string().c_str(), "rb");
|
||||
if (fp == nullptr) return;
|
||||
std::fseek(fp, 0, SEEK_END);
|
||||
int len = std::ftell(fp);
|
||||
std::rewind(fp);
|
||||
std::vector<uint8_t> ret;
|
||||
ret.resize(len);
|
||||
std::fread(ret.data(), 1, len, fp);
|
||||
std::fclose(fp);*/
|
||||
cb(path.string());
|
||||
}
|
||||
|
||||
void Cache::GetFileFromURL(std::string url, callback_type cb) {
|
||||
auto cache_path = m_tmp_path / SanitizeString(url);
|
||||
if (std::filesystem::exists(cache_path)) {
|
||||
RespondFromPath(cache_path, cb);
|
||||
m_futures.push_back(std::async(std::launch::async, [this, cache_path, cb]() {
|
||||
RespondFromPath(cache_path, cb); }));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,44 +1,68 @@
|
||||
#include "imgmanager.hpp"
|
||||
#include "util.hpp"
|
||||
|
||||
ImageManager::ImageManager() {
|
||||
m_cb_dispatcher.connect(sigc::mem_fun(*this, &ImageManager::RunCallbacks));
|
||||
}
|
||||
|
||||
Cache &ImageManager::GetCache() {
|
||||
return m_cache;
|
||||
}
|
||||
|
||||
void ImageManager::LoadFromURL(std::string url, std::function<void(Glib::RefPtr<Gdk::Pixbuf>)> cb) {
|
||||
/*if (m_pixs.find(url) != m_pixs.end()) {
|
||||
cb(m_pixs.at(url));
|
||||
return;
|
||||
}*/
|
||||
Glib::RefPtr<Gdk::Pixbuf> ImageManager::ReadFileToPixbuf(std::string path) {
|
||||
const auto &data = ReadWholeFile(path);
|
||||
if (data.size() == 0) return Glib::RefPtr<Gdk::Pixbuf>(nullptr);
|
||||
auto loader = Gdk::PixbufLoader::create();
|
||||
loader->signal_size_prepared().connect([&loader](int w, int h) {
|
||||
int cw, ch;
|
||||
GetImageDimensions(w, h, cw, ch); // what could go wrong
|
||||
loader->set_size(cw, ch);
|
||||
});
|
||||
loader->write(static_cast<const guint8 *>(data.data()), data.size());
|
||||
loader->close();
|
||||
auto buf = loader->get_pixbuf();
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
void ImageManager::LoadFromURL(std::string url, callback_type cb) {
|
||||
m_cache.GetFileFromURL(url, [this, url, cb](std::string path) {
|
||||
try {
|
||||
auto buf = Gdk::Pixbuf::create_from_file(path);
|
||||
//m_pixs[url] = buf;
|
||||
cb(buf);
|
||||
auto buf = ReadFileToPixbuf(path);
|
||||
m_cb_mutex.lock();
|
||||
m_cb_queue.push(std::make_pair(buf, cb));
|
||||
m_cb_dispatcher.emit();
|
||||
m_cb_mutex.unlock();
|
||||
} catch (std::exception &e) {
|
||||
fprintf(stderr, "err loading pixbuf from %s: %s\n", path.c_str(), e.what());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void ImageManager::RunCallbacks() {
|
||||
m_cb_mutex.lock();
|
||||
const auto &pair = m_cb_queue.front();
|
||||
pair.second(pair.first);
|
||||
m_cb_queue.pop();
|
||||
m_cb_mutex.unlock();
|
||||
}
|
||||
|
||||
Glib::RefPtr<Gdk::Pixbuf> ImageManager::GetFromURLIfCached(std::string url) {
|
||||
std::string path = m_cache.GetPathIfCached(url);
|
||||
if (path != "")
|
||||
return Gdk::Pixbuf::create_from_file(path);
|
||||
//if (m_pixs.find(url) != m_pixs.end())
|
||||
// return m_pixs.at(url);
|
||||
return ReadFileToPixbuf(path);
|
||||
|
||||
return Glib::RefPtr<Gdk::Pixbuf>(nullptr);
|
||||
}
|
||||
|
||||
Glib::RefPtr<Gdk::Pixbuf> ImageManager::GetPlaceholder(int size) {
|
||||
std::string name = "/placeholder" + std::to_string(size);
|
||||
//if (m_pixs.find(name) != m_pixs.end())
|
||||
// return m_pixs.at(name);
|
||||
if (m_pixs.find(name) != m_pixs.end())
|
||||
return m_pixs.at(name);
|
||||
|
||||
try {
|
||||
auto buf = Gdk::Pixbuf::create_from_file("res/decamarks.png", size, size);
|
||||
// m_pixs[name] = buf;
|
||||
m_pixs[name] = buf;
|
||||
return buf;
|
||||
} catch (std::exception &e) {
|
||||
fprintf(stderr, "error loading placeholder\n");
|
||||
|
||||
@@ -2,17 +2,30 @@
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <functional>
|
||||
#include <queue>
|
||||
#include <gtkmm.h>
|
||||
#include "filecache.hpp"
|
||||
|
||||
class ImageManager {
|
||||
public:
|
||||
ImageManager();
|
||||
|
||||
using callback_type = std::function<void(Glib::RefPtr<Gdk::Pixbuf>)>;
|
||||
|
||||
Cache &GetCache();
|
||||
void LoadFromURL(std::string url, std::function<void(Glib::RefPtr<Gdk::Pixbuf>)> cb);
|
||||
void LoadFromURL(std::string url, callback_type cb);
|
||||
Glib::RefPtr<Gdk::Pixbuf> GetFromURLIfCached(std::string url);
|
||||
Glib::RefPtr<Gdk::Pixbuf> GetPlaceholder(int size);
|
||||
|
||||
private:
|
||||
Glib::RefPtr<Gdk::Pixbuf> ReadFileToPixbuf(std::string path);
|
||||
|
||||
mutable std::mutex m_load_mutex;
|
||||
void RunCallbacks();
|
||||
Glib::Dispatcher m_cb_dispatcher;
|
||||
mutable std::mutex m_cb_mutex;
|
||||
std::queue<std::pair<Glib::RefPtr<Gdk::Pixbuf>, callback_type>> m_cb_queue;
|
||||
|
||||
std::unordered_map<std::string, Glib::RefPtr<Gdk::Pixbuf>> m_pixs;
|
||||
Cache m_cache;
|
||||
};
|
||||
|
||||
31
util.hpp
31
util.hpp
@@ -29,6 +29,37 @@ inline void LaunchBrowser(std::string url) {
|
||||
#endif
|
||||
}
|
||||
|
||||
inline void GetImageDimensions(int inw, int inh, int &outw, int &outh, int clampw = 400, int clamph = 300) {
|
||||
const auto frac = static_cast<float>(inw) / inh;
|
||||
|
||||
outw = inw;
|
||||
outh = inh;
|
||||
|
||||
if (outw > clampw) {
|
||||
outw = clampw;
|
||||
outh = clampw / frac;
|
||||
}
|
||||
|
||||
if (outh > clamph) {
|
||||
outh = clamph;
|
||||
outw = clamph * frac;
|
||||
}
|
||||
}
|
||||
|
||||
inline std::vector<uint8_t> ReadWholeFile(std::string path) {
|
||||
std::vector<uint8_t> ret;
|
||||
FILE *fp = std::fopen(path.c_str(), "rb");
|
||||
if (fp == nullptr)
|
||||
return ret;
|
||||
std::fseek(fp, 0, SEEK_END);
|
||||
int len = std::ftell(fp);
|
||||
std::rewind(fp);
|
||||
ret.resize(len);
|
||||
std::fread(ret.data(), 1, ret.size(), fp);
|
||||
std::fclose(fp);
|
||||
return ret;
|
||||
}
|
||||
|
||||
inline std::string HumanReadableBytes(uint64_t bytes) {
|
||||
constexpr static const char *x[] = { "B", "KB", "MB", "GB", "TB" };
|
||||
int order = 0;
|
||||
|
||||
Reference in New Issue
Block a user