aboutsummaryrefslogtreecommitdiff
path: root/src/AsyncImageLoader.cpp
diff options
context:
space:
mode:
authordec05eba <dec05eba@protonmail.com>2021-07-11 20:59:58 +0200
committerdec05eba <dec05eba@protonmail.com>2021-07-11 21:37:10 +0200
commit97df498b30d8580d4b74582a634562f996003dd0 (patch)
treee40bb52d0709e435c66d49126780044ca4c4a3b0 /src/AsyncImageLoader.cpp
parent9d71f913744ab567a49195a43c525c0d494fe084 (diff)
Remove dependency on imagemagick. Use stb resize to downscale image.
Diffstat (limited to 'src/AsyncImageLoader.cpp')
-rw-r--r--src/AsyncImageLoader.cpp105
1 files changed, 82 insertions, 23 deletions
diff --git a/src/AsyncImageLoader.cpp b/src/AsyncImageLoader.cpp
index 9e8d090..3e00459 100644
--- a/src/AsyncImageLoader.cpp
+++ b/src/AsyncImageLoader.cpp
@@ -6,48 +6,107 @@
#include "../include/SfmlFixes.hpp"
#include "../external/hash-library/sha256.h"
+#include <unistd.h>
+#include <sys/prctl.h>
#include <sys/stat.h>
+#include <sys/wait.h>
+#include <signal.h>
#include <malloc.h>
#include <assert.h>
+#include <cmath>
+
+#define STB_IMAGE_RESIZE_IMPLEMENTATION
+#include "../external/stb/stb_image_resize.h"
namespace QuickMedia {
+ static bool webp_to_png(const Path &thumbnail_path, const Path &destination_path) {
+ const char *args[] = { "ffmpeg", "-y", "-v", "quiet", "-i", thumbnail_path.data.c_str(), "--", destination_path.data.c_str(), nullptr};
+ int res = exec_program(args, nullptr, nullptr);
+ if(res != 0)
+ return false;
+
+ return true;
+ }
+
bool create_thumbnail(const Path &thumbnail_path, const Path &thumbnail_path_resized, sf::Vector2i resize_target_size, ContentType content_type) {
Path input_path = thumbnail_path;
- // TODO: Remove this when imagemagick supports webp
- // Convert webp to png
- bool remove_tmp_input = false;
if(content_type == ContentType::IMAGE_WEBP) {
Path result_path_tmp = thumbnail_path_resized;
result_path_tmp.append(".tmp.png");
-
- const char *args[] = { "ffmpeg", "-y", "-v", "quiet", "-i", input_path.data.c_str(), "--", result_path_tmp.data.c_str(), nullptr};
- int res = exec_program(args, nullptr, nullptr);
- if(res != 0)
+ if(!webp_to_png(thumbnail_path, result_path_tmp))
return false;
-
input_path = std::move(result_path_tmp);
- remove_tmp_input = true;
}
- // > is to only shrink image if smaller than the target size
- std::string new_size = std::to_string(resize_target_size.x) + "x" + std::to_string(resize_target_size.y) + ">";
+ // Fork here because we want the memory allocated to be completely deallocated.
+ // TODO: Find a way to do that without fork.
+ pid_t parent_pid = getpid();
+ pid_t pid = fork();
+ if(pid == -1) {
+ perror("Failed to fork");
+ return false;
+ } else if(pid == 0) { // child
+ if(prctl(PR_SET_PDEATHSIG, SIGTERM) == -1) {
+ perror("prctl(PR_SET_PDEATHSIG, SIGTERM) failed");
+ _exit(127);
+ }
+
+ /* Test if the parent died before the above call to prctl */
+ if(getppid() != parent_pid)
+ _exit(127);
+
+ sf::Image image;
+ if(!image.loadFromFile(input_path.data) || image.getSize().x == 0 || image.getSize().y == 0) {
+ fprintf(stderr, "Failed to load %s\n", input_path.data.c_str());
+ _exit(1);
+ }
+
+ Path result_path_tmp = thumbnail_path_resized;
+ result_path_tmp.append(".tmp.png");
+
+ if(image.getSize().x <= (unsigned int)resize_target_size.x && image.getSize().y <= (unsigned int)resize_target_size.y) {
+ int res = symlink(input_path.data.c_str(), result_path_tmp.data.c_str());
+ if(res == -1 && errno != EEXIST) {
+ fprintf(stderr, "Failed to save %s\n", thumbnail_path_resized.data.c_str());
+ _exit(1);
+ }
+ } else {
+ sf::Vector2u clamped_size = clamp_to_size(image.getSize(), sf::Vector2u(resize_target_size.x, resize_target_size.y));
+ unsigned char *output_pixels = new unsigned char[clamped_size.x * clamped_size.y * 4];
+ stbir_resize_uint8(image.getPixelsPtr(), image.getSize().x, image.getSize().y, 0, output_pixels, clamped_size.x, clamped_size.y, 0, 4);
+
+ // TODO: Remove this and use stb write to remove this unecessary extra copy of the data and write the data directly to file after converting it to png
+ sf::Image destination_image;
+ destination_image.create(clamped_size.x, clamped_size.y, output_pixels);
+ if(!destination_image.saveToFile(result_path_tmp.data)) {
+ fprintf(stderr, "Failed to save %s\n", thumbnail_path_resized.data.c_str());
+ _exit(1);
+ }
+ }
+
+ if(rename_atomic(result_path_tmp.data.c_str(), thumbnail_path_resized.data.c_str()) == 0)
+ _exit(0);
+ else
+ _exit(1);
+ }
+
+ // parent
- // We only want the first frame if its a gif
- Path thumbnail_path_first_frame = input_path;
- thumbnail_path_first_frame.append("[0]");
+ int status = 0;
+ if(waitpid(pid, &status, 0) == -1) {
+ perror("waitpid failed");
+ return false;
+ }
- Path result_path_tmp = thumbnail_path_resized;
- result_path_tmp.append(".tmp");
+ if(!WIFEXITED(status))
+ return false;
- const char *args[] = { "convert", thumbnail_path_first_frame.data.c_str(), "-thumbnail", new_size.c_str(), result_path_tmp.data.c_str(), nullptr};
- int convert_res = exec_program(args, nullptr, nullptr);
- if(remove_tmp_input)
- remove(input_path.data.c_str());
- if(convert_res == 0 && rename_atomic(result_path_tmp.data.c_str(), thumbnail_path_resized.data.c_str()) == 0)
- return true;
- else
+ int exit_status = WEXITSTATUS(status);
+ if(exit_status != 0)
return false;
+
+ return true;
}
// Create thumbnail and load it. On failure load the original image