diff options
author | dec05eba <dec05eba@protonmail.com> | 2020-10-19 11:02:26 +0200 |
---|---|---|
committer | dec05eba <dec05eba@protonmail.com> | 2020-10-19 11:02:26 +0200 |
commit | b233f24fe103a745eb6487e236b7cb08269a6cb3 (patch) | |
tree | fbbc54060727a12769048ab5741d6f234686dbcd /src | |
parent | 386d16a95a1306decabf6e9764309caf0d2818e3 (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.cpp | 28 | ||||
-rw-r--r-- | src/QuickMedia.cpp | 20 | ||||
-rw-r--r-- | src/plugins/Fourchan.cpp | 14 | ||||
-rw-r--r-- | src/plugins/Matrix.cpp | 31 |
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; } |