aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordec05eba <dec05eba@protonmail.com>2020-10-19 11:02:26 +0200
committerdec05eba <dec05eba@protonmail.com>2020-10-19 11:02:26 +0200
commitb233f24fe103a745eb6487e236b7cb08269a6cb3 (patch)
treefbbc54060727a12769048ab5741d6f234686dbcd /src
parent386d16a95a1306decabf6e9764309caf0d2818e3 (diff)
Change thumbnail creation from nearest neighbor to linear interpolation, set body thumbnail size for 4chan and matrix (if available)
Diffstat (limited to 'src')
-rw-r--r--src/AsyncImageLoader.cpp28
-rw-r--r--src/QuickMedia.cpp20
-rw-r--r--src/plugins/Fourchan.cpp14
-rw-r--r--src/plugins/Matrix.cpp31
4 files changed, 84 insertions, 9 deletions
diff --git a/src/AsyncImageLoader.cpp b/src/AsyncImageLoader.cpp
index 8f771e7..00ca7ee 100644
--- a/src/AsyncImageLoader.cpp
+++ b/src/AsyncImageLoader.cpp
@@ -19,6 +19,7 @@ namespace QuickMedia {
return sf::Vector2u(vec.x, vec.y);
}
+ // Linear interpolation
static void copy_resize(const sf::Image &source, sf::Image &destination, sf::Vector2u destination_size) {
const sf::Vector2u source_size = source.getSize();
if(source_size.x == 0 || source_size.y == 0 || destination_size.x == 0 || destination_size.y == 0)
@@ -33,14 +34,33 @@ namespace QuickMedia {
sf::Uint32 *destination_pixel = destination_pixels;
for(unsigned int y = 0; y < destination_size.y; ++y) {
for(unsigned int x = 0; x < destination_size.x; ++x) {
- int scaled_x = ((float)x / (float)destination_size.x) * source_size.x;
- int scaled_y = ((float)y / (float)destination_size.y) * source_size.y;
+ int scaled_x_start = ((float)x / (float)destination_size.x) * source_size.x;
+ int scaled_y_start = ((float)y / (float)destination_size.y) * source_size.y;
+ int scaled_x_end = ((float)(x + 1) / (float)destination_size.x) * source_size.x;
+ int scaled_y_end = ((float)(y + 1) / (float)destination_size.y) * source_size.y;
//float scaled_x = x * width_ratio;
//float scaled_y = y * height_ratio;
//sf::Uint32 *source_pixel = (sf::Uint32*)(source_pixels + (int)(scaled_x + scaled_y * source_size.x) * 4);
- sf::Uint32 *source_pixel = (sf::Uint32*)(source_pixels + (scaled_x + scaled_y * source_size.x) * 4);
- *destination_pixel = *source_pixel;
+ sf::Uint32 sum_red = 0;
+ sf::Uint32 sum_green = 0;
+ sf::Uint32 sum_blue = 0;
+ sf::Uint32 sum_alpha = 0;
+ sf::Uint32 num_colors = (scaled_x_end - scaled_x_start) * (scaled_y_end - scaled_y_start);
+ for(int yy = scaled_y_start; yy < scaled_y_end; ++yy) {
+ for(int xx = scaled_x_start; xx < scaled_x_end; ++xx) {
+ sf::Uint32 *source_pixel = (sf::Uint32*)(source_pixels + (xx + yy * source_size.x) * 4);
+ sum_red += (*source_pixel >> 24);
+ sum_green += ((*source_pixel >> 16) & 0xFF);
+ sum_blue += ((*source_pixel >> 8) & 0xFF);
+ sum_alpha += (*source_pixel & 0xFF);
+ }
+ }
+ sum_red /= num_colors;
+ sum_green /= num_colors;
+ sum_blue /= num_colors;
+ sum_alpha /= num_colors;
+ *destination_pixel = (sum_red << 24) | (sum_green << 16) | (sum_blue << 8) | sum_alpha;
++destination_pixel;
}
}
diff --git a/src/QuickMedia.cpp b/src/QuickMedia.cpp
index 6e4ee51..0b39673 100644
--- a/src/QuickMedia.cpp
+++ b/src/QuickMedia.cpp
@@ -2894,6 +2894,16 @@ namespace QuickMedia {
return str;
}
+ static sf::Vector2f to_vec2f(const sf::Vector2i &vec) {
+ return sf::Vector2f(vec.x, vec.y);
+ }
+
+ static sf::Vector2i to_vec2i(const sf::Vector2f &vec) {
+ return sf::Vector2i(vec.x, vec.y);
+ }
+
+ static const sf::Vector2i CHAT_MESSAGE_THUMBNAIL_MAX_SIZE(600, 337);
+
static std::shared_ptr<BodyItem> message_to_body_item(Message *message, UserInfo *me) {
auto body_item = BodyItem::create("");
body_item->set_author(message->user->display_name);
@@ -2902,11 +2912,12 @@ namespace QuickMedia {
text = remove_reply_formatting(text);
body_item->set_description(std::move(text));
body_item->set_timestamp(message->timestamp);
- if(!message->thumbnail_url.empty())
+ if(!message->thumbnail_url.empty()) {
body_item->thumbnail_url = message->thumbnail_url;
- else if(!message->url.empty() && message->type == MessageType::IMAGE)
+ body_item->thumbnail_size = to_vec2i(clamp_to_size(to_vec2f(message->thumbnail_size), to_vec2f(CHAT_MESSAGE_THUMBNAIL_MAX_SIZE)));
+ } else if(!message->url.empty() && message->type == MessageType::IMAGE) {
body_item->thumbnail_url = message->url;
- else {
+ } else {
body_item->thumbnail_url = message->user->avatar_url;
body_item->thumbnail_mask_type = ThumbnailMaskType::CIRCLE;
// if construct is not configured to use ImageMagic then it wont give thumbnails of size 32x32 even when requested and the spec says that the server SHOULD do that
@@ -2943,8 +2954,7 @@ namespace QuickMedia {
messages_tab.type = ChatTabType::MESSAGES;
messages_tab.body = std::make_unique<Body>(this, font.get(), bold_font.get(), cjk_font.get());
messages_tab.body->draw_thumbnails = true;
- messages_tab.body->thumbnail_resize_target_size.x = 600;
- messages_tab.body->thumbnail_resize_target_size.y = 337;
+ messages_tab.body->thumbnail_resize_target_size = CHAT_MESSAGE_THUMBNAIL_MAX_SIZE;
messages_tab.body->thumbnail_mask_shader = &circle_mask_shader;
//messages_tab.body->line_separator_color = sf::Color::Transparent;
messages_tab.text = sf::Text("Messages", *font, tab_text_size);
diff --git a/src/plugins/Fourchan.cpp b/src/plugins/Fourchan.cpp
index 2938319..7f8008c 100644
--- a/src/plugins/Fourchan.cpp
+++ b/src/plugins/Fourchan.cpp
@@ -252,6 +252,13 @@ namespace QuickMedia {
// "s" means small, that's the url 4chan uses for thumbnails.
// thumbnails always has .jpg extension even if they are gifs or webm.
body_item->thumbnail_url = fourchan_image_url + url + "/" + std::to_string(tim.asInt64()) + "s.jpg";
+
+ sf::Vector2i thumbnail_size(64, 64);
+ const Json::Value &tn_w = thread["tn_w"];
+ const Json::Value &tn_h = thread["tn_h"];
+ if(tn_w.isNumeric() && tn_h.isNumeric())
+ thumbnail_size = sf::Vector2i(tn_w.asInt() * 0.5, tn_h.asInt() * 0.5);
+ body_item->thumbnail_size = std::move(thumbnail_size);
}
result_items.push_back(std::move(body_item));
@@ -438,6 +445,13 @@ namespace QuickMedia {
body_item->thumbnail_url = fourchan_image_url + board_id + "/" + tim_str + "s.jpg";
body_item->attached_content_url = fourchan_image_url + board_id + "/" + tim_str + ext_str;
cached_media_urls.push_back(body_item->attached_content_url);
+
+ sf::Vector2i thumbnail_size(64, 64);
+ const Json::Value &tn_w = post["tn_w"];
+ const Json::Value &tn_h = post["tn_h"];
+ if(tn_w.isNumeric() && tn_h.isNumeric())
+ thumbnail_size = sf::Vector2i(tn_w.asInt(), tn_h.asInt());
+ body_item->thumbnail_size = std::move(thumbnail_size);
}
++body_item_index;
diff --git a/src/plugins/Matrix.cpp b/src/plugins/Matrix.cpp
index f7364d1..bfdd496 100644
--- a/src/plugins/Matrix.cpp
+++ b/src/plugins/Matrix.cpp
@@ -364,6 +364,34 @@ namespace QuickMedia {
return "";
}
+ static bool message_content_extract_thumbnail_size(const rapidjson::Value &content_json, sf::Vector2i &thumbnail_size) {
+ const rapidjson::Value &info_json = GetMember(content_json, "info");
+ if(!info_json.IsObject())
+ return false;
+
+ bool found_resolution = false;
+ const rapidjson::Value &w_json = GetMember(info_json, "w");
+ const rapidjson::Value &h_json = GetMember(info_json, "h");
+ if(w_json.IsNumber() && h_json.IsNumber()) {
+ thumbnail_size.x = w_json.GetInt();
+ thumbnail_size.y = h_json.GetInt();
+ found_resolution = true;
+ }
+
+ const rapidjson::Value &thumbnail_info_json = GetMember(info_json, "thumbnail_info");
+ if(thumbnail_info_json.IsObject()) {
+ const rapidjson::Value &w_json = GetMember(thumbnail_info_json, "w");
+ const rapidjson::Value &h_json = GetMember(thumbnail_info_json, "h");
+ if(w_json.IsNumber() && h_json.IsNumber()) {
+ thumbnail_size.x = w_json.GetInt();
+ thumbnail_size.y = h_json.GetInt();
+ found_resolution = true;
+ }
+ }
+
+ return found_resolution;
+ }
+
// TODO: Is this really the proper way to check for username mentions?
static bool is_username_seperating_character(char c) {
switch(c) {
@@ -551,6 +579,7 @@ namespace QuickMedia {
message->url = homeserver + "/_matrix/media/r0/download/" + (url_json.GetString() + 6);
message->thumbnail_url = message_content_extract_thumbnail_url(*content_json, homeserver);
+ message_content_extract_thumbnail_size(*content_json, message->thumbnail_size);
message->type = MessageType::IMAGE;
} else if(strcmp(content_type.GetString(), "m.video") == 0) {
const rapidjson::Value &url_json = GetMember(*content_json, "url");
@@ -559,6 +588,7 @@ namespace QuickMedia {
message->url = homeserver + "/_matrix/media/r0/download/" + (url_json.GetString() + 6);
message->thumbnail_url = message_content_extract_thumbnail_url(*content_json, homeserver);
+ message_content_extract_thumbnail_size(*content_json, message->thumbnail_size);
message->type = MessageType::VIDEO;
} else if(strcmp(content_type.GetString(), "m.audio") == 0) {
const rapidjson::Value &url_json = GetMember(*content_json, "url");
@@ -587,6 +617,7 @@ namespace QuickMedia {
message->type = MessageType::TEXT;
message->thumbnail_url = message_content_extract_thumbnail_url(*content_json, homeserver);
+ message_content_extract_thumbnail_size(*content_json, message->thumbnail_size);
} else {
return nullptr;
}