diff options
m--------- | depends/dchat_core | 0 | ||||
-rw-r--r-- | include/GtkGif.hpp | 2 | ||||
-rw-r--r-- | include/GtkScaledImage.hpp | 27 | ||||
-rw-r--r-- | src/ChatMessage.cpp | 2 | ||||
-rw-r--r-- | src/DynamicImage.cpp | 20 | ||||
-rw-r--r-- | src/GlobalCache.cpp | 12 | ||||
-rw-r--r-- | src/GtkGif.cpp | 11 | ||||
-rw-r--r-- | src/GtkScaledImage.cpp | 62 |
8 files changed, 126 insertions, 10 deletions
diff --git a/depends/dchat_core b/depends/dchat_core -Subproject 6d0a59570338542818b87b480635cd01c6e3a65 +Subproject e9b8d41595f9181322d7bed0405c0b96d756532 diff --git a/include/GtkGif.hpp b/include/GtkGif.hpp index a4a28d7..7b1de40 100644 --- a/include/GtkGif.hpp +++ b/include/GtkGif.hpp @@ -12,7 +12,7 @@ namespace dchat GtkGif(StringView fileContent); virtual ~GtkGif(){} - void draw(const Cairo::RefPtr<Cairo::Context> &cairo, int width, int height); + void draw(const Cairo::RefPtr<Cairo::Context> &cairo, int width, int height, bool circularMask); protected: // Return false if texture creation failed bool createTexture(int width, int height) override; diff --git a/include/GtkScaledImage.hpp b/include/GtkScaledImage.hpp new file mode 100644 index 0000000..ceb0b7d --- /dev/null +++ b/include/GtkScaledImage.hpp @@ -0,0 +1,27 @@ +#pragma once + +#include <dchat/StaticImage.hpp> +#include <cairomm/context.h> +#include <cairomm/surface.h> +#include <gdkmm/pixbuf.h> +#include <stdexcept> + +namespace dchat +{ + class GtkScaledImageException : public std::runtime_error + { + public: + GtkScaledImageException(const std::string &errMsg) : std::runtime_error(errMsg) {} + }; + + class GtkScaledImage : public StaticImage + { + public: + // Throws GtkScaledImageException on error + GtkScaledImage(const boost::filesystem::path &filepath); + virtual ~GtkScaledImage(){} + void draw(const Cairo::RefPtr<Cairo::Context> &cairo, int width, int height, bool circularMask); + private: + Cairo::RefPtr<Cairo::ImageSurface> surface; + }; +}
\ No newline at end of file diff --git a/src/ChatMessage.cpp b/src/ChatMessage.cpp index aa96abd..638cfa2 100644 --- a/src/ChatMessage.cpp +++ b/src/ChatMessage.cpp @@ -10,7 +10,7 @@ namespace dchat avatar.set_halign(Gtk::ALIGN_START); avatar.set_valign(Gtk::ALIGN_START); avatar.set_size_request(50, 50); - avatar.url = "https://discordemoji.com/assets/emoji/PoggersHype.gif"; + avatar.url = "https://discordemoji.com/assets/emoji/PeepoHide.png"; username.set_selectable(true); username.set_alignment(Gtk::ALIGN_START, Gtk::ALIGN_START); diff --git a/src/DynamicImage.cpp b/src/DynamicImage.cpp index 8759497..0a31d36 100644 --- a/src/DynamicImage.cpp +++ b/src/DynamicImage.cpp @@ -1,6 +1,7 @@ #include "../include/DynamicImage.hpp" #include "../include/GlobalCache.hpp" #include "../include/GtkGif.hpp" +#include "../include/GtkScaledImage.hpp" namespace dchat { @@ -18,8 +19,23 @@ namespace dchat auto result = getGlobalCache().getContentByUrl(url, downloadLimitBytes); if(result.type == ContentByUrlResult::Type::CACHED && result.gif) { - GtkGif *gif = (GtkGif*)result.gif; - gif->draw(cairo, alloc.get_width(), alloc.get_height()); + switch(result.cachedType) + { + case ContentByUrlResult::CachedType::STATIC_IMAGE: + { + GtkScaledImage *staticImage = (GtkScaledImage*)result.staticImage; + staticImage->draw(cairo, alloc.get_width(), alloc.get_height(), true); + break; + } + case ContentByUrlResult::CachedType::GIF: + { + GtkGif *gif = (GtkGif*)result.gif; + gif->draw(cairo, alloc.get_width(), alloc.get_height(), true); + break; + } + default: + break; + } } } queue_draw(); diff --git a/src/GlobalCache.cpp b/src/GlobalCache.cpp index e627a33..b287738 100644 --- a/src/GlobalCache.cpp +++ b/src/GlobalCache.cpp @@ -1,5 +1,6 @@ #include "../include/GlobalCache.hpp" #include "../include/GtkGif.hpp" +#include "../include/GtkScaledImage.hpp" namespace dchat { @@ -8,10 +9,17 @@ namespace dchat { if(!cache) { - cache = new Cache([](StringView fileContent) + auto createGifFunc = [](StringView fileContent) { return new GtkGif(fileContent); - }); + }; + + auto createStaticImageFunc = [](const boost::filesystem::path &filepath) + { + return new GtkScaledImage(filepath); + }; + + cache = new Cache(createGifFunc, createStaticImageFunc); } return *cache; } diff --git a/src/GtkGif.cpp b/src/GtkGif.cpp index 92aae88..5800e29 100644 --- a/src/GtkGif.cpp +++ b/src/GtkGif.cpp @@ -31,13 +31,16 @@ namespace dchat surface->mark_dirty(); } - void GtkGif::draw(const Cairo::RefPtr<Cairo::Context> &cairo, int width, int height) + void GtkGif::draw(const Cairo::RefPtr<Cairo::Context> &cairo, int width, int height, bool circularMask) { update(); - int minSize = std::min(width/2, height/2); - cairo->arc(width/2, height/2, minSize, 0.0, 2.0 * M_PI); - cairo->clip(); + if(circularMask) + { + int minSize = std::min(width/2, height/2); + cairo->arc(width/2, height/2, minSize, 0.0, 2.0 * M_PI); + cairo->clip(); + } double scaleX = (double)width / (double)surface->get_width(); double scaleY = (double)height / (double)surface->get_height(); diff --git a/src/GtkScaledImage.cpp b/src/GtkScaledImage.cpp new file mode 100644 index 0000000..6f41c11 --- /dev/null +++ b/src/GtkScaledImage.cpp @@ -0,0 +1,62 @@ +#include "../include/GtkScaledImage.hpp" +#include <gdkmm/pixbuf.h> + +namespace dchat +{ + GtkScaledImage::GtkScaledImage(const boost::filesystem::path &filepath) + { + try + { + auto pixbuf = Gdk::Pixbuf::create_from_file(filepath.string()); + Cairo::Format format = pixbuf->get_has_alpha() ? Cairo::Format::FORMAT_ARGB32 : Cairo::Format::FORMAT_RGB24; + surface = Cairo::ImageSurface::create(format, pixbuf->get_width(), pixbuf->get_height()); + unsigned char *pixels = surface->get_data(); + surface->flush(); + char *p = (char*)pixbuf->get_pixels(); + // TODO: Optimize this + if(format == Cairo::Format::FORMAT_ARGB32) + { + for(int i = 0; i < surface->get_stride() * surface->get_height(); i += 4) + { + pixels[i + 0] = p[i + 2]; + pixels[i + 1] = p[i + 1]; + pixels[i + 2] = p[i + 0]; + pixels[i + 3] = p[i + 3]; + } + } + else + { + for(int i = 0; i < surface->get_stride() * surface->get_height(); i += 3) + { + pixels[i + 0] = p[i + 2]; + pixels[i + 1] = p[i + 1]; + pixels[i + 2] = p[i + 0]; + } + } + //memcpy(pixels, textureData, surface->get_stride() * surface->get_height()); + surface->mark_dirty(); + } + catch(std::exception &e) + { + std::string errMsg = "Failed to create scaled image, reason: "; + errMsg += e.what(); + throw GtkScaledImageException(errMsg); + } + } + + void GtkScaledImage::draw(const Cairo::RefPtr<Cairo::Context> &cairo, int width, int height, bool circularMask) + { + if(circularMask) + { + int minSize = std::min(width/2, height/2); + cairo->arc(width/2, height/2, minSize, 0.0, 2.0 * M_PI); + cairo->clip(); + } + + double scaleX = (double)width / (double)surface->get_width(); + double scaleY = (double)height / (double)surface->get_height(); + cairo->scale(scaleX, scaleY); + cairo->set_source(surface, 0.0, 0.0); + cairo->paint(); + } +}
\ No newline at end of file |