aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/AsyncImageLoader.cpp105
-rw-r--r--src/Program.cpp23
2 files changed, 82 insertions, 46 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
diff --git a/src/Program.cpp b/src/Program.cpp
index 5daf25c..513ce8c 100644
--- a/src/Program.cpp
+++ b/src/Program.cpp
@@ -1,7 +1,6 @@
#include "../include/Program.hpp"
#include <unistd.h>
#include <sys/wait.h>
-#include <sys/prctl.h>
#include <errno.h>
#include <string.h>
#include <stdio.h>
@@ -94,8 +93,6 @@ int exec_program_pipe(const char **args, ReadProgram *read_program) {
return -2;
}
- pid_t parent_pid = getpid();
-
pid_t pid = vfork();
if(pid == -1) {
perror("Failed to vfork");
@@ -103,15 +100,6 @@ int exec_program_pipe(const char **args, ReadProgram *read_program) {
close(fd[WRITE_END]);
return -3;
} 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);
-
dup2(fd[WRITE_END], STDOUT_FILENO);
close(fd[READ_END]);
close(fd[WRITE_END]);
@@ -236,8 +224,6 @@ int exec_program_async(const char **args, pid_t *result_process_id) {
if(args[0] == NULL)
return -1;
- pid_t parent_pid = getpid();
-
pid_t pid = vfork();
if(pid == -1) {
int err = errno;
@@ -245,15 +231,6 @@ int exec_program_async(const char **args, pid_t *result_process_id) {
return -err;
} else if(pid == 0) { /* child */
if(result_process_id) {
- 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);
-
execvp(args[0], (char* const*)args);
perror("execvp");
_exit(127);