add lossy qoi encoding using rdo
Some checks are pending
ContinuousDelivery / linux-ubuntu (push) Waiting to run
ContinuousDelivery / android (map[ndk_abi:arm64-v8a vcpkg_toolkit:arm64-android-23]) (push) Waiting to run
ContinuousDelivery / android (map[ndk_abi:armeabi-v7a vcpkg_toolkit:arm-neon-android-23]) (push) Waiting to run
ContinuousDelivery / android (map[ndk_abi:x86_64 vcpkg_toolkit:x64-android-23]) (push) Waiting to run
ContinuousDelivery / windows (push) Waiting to run
ContinuousDelivery / windows-asan (push) Waiting to run
ContinuousDelivery / dumpsyms (push) Blocked by required conditions
ContinuousDelivery / release (push) Blocked by required conditions
ContinuousIntegration / linux (push) Waiting to run
ContinuousIntegration / android (map[ndk_abi:arm64-v8a vcpkg_toolkit:arm64-android-23]) (push) Waiting to run
ContinuousIntegration / android (map[ndk_abi:armeabi-v7a vcpkg_toolkit:arm-neon-android-23]) (push) Waiting to run
ContinuousIntegration / android (map[ndk_abi:x86_64 vcpkg_toolkit:x64-android-23]) (push) Waiting to run
ContinuousIntegration / macos (push) Waiting to run
ContinuousIntegration / windows (push) Waiting to run
Some checks are pending
ContinuousDelivery / linux-ubuntu (push) Waiting to run
ContinuousDelivery / android (map[ndk_abi:arm64-v8a vcpkg_toolkit:arm64-android-23]) (push) Waiting to run
ContinuousDelivery / android (map[ndk_abi:armeabi-v7a vcpkg_toolkit:arm-neon-android-23]) (push) Waiting to run
ContinuousDelivery / android (map[ndk_abi:x86_64 vcpkg_toolkit:x64-android-23]) (push) Waiting to run
ContinuousDelivery / windows (push) Waiting to run
ContinuousDelivery / windows-asan (push) Waiting to run
ContinuousDelivery / dumpsyms (push) Blocked by required conditions
ContinuousDelivery / release (push) Blocked by required conditions
ContinuousIntegration / linux (push) Waiting to run
ContinuousIntegration / android (map[ndk_abi:arm64-v8a vcpkg_toolkit:arm64-android-23]) (push) Waiting to run
ContinuousIntegration / android (map[ndk_abi:armeabi-v7a vcpkg_toolkit:arm-neon-android-23]) (push) Waiting to run
ContinuousIntegration / android (map[ndk_abi:x86_64 vcpkg_toolkit:x64-android-23]) (push) Waiting to run
ContinuousIntegration / macos (push) Waiting to run
ContinuousIntegration / windows (push) Waiting to run
This commit is contained in:
parent
9878cabc9c
commit
bd7ee1c167
1
external/CMakeLists.txt
vendored
1
external/CMakeLists.txt
vendored
@ -25,6 +25,7 @@ add_subdirectory(./implot)
|
|||||||
add_subdirectory(./stb)
|
add_subdirectory(./stb)
|
||||||
add_subdirectory(./libwebp)
|
add_subdirectory(./libwebp)
|
||||||
add_subdirectory(./qoi)
|
add_subdirectory(./qoi)
|
||||||
|
add_subdirectory(./libqoirdo)
|
||||||
add_subdirectory(./sdl_image)
|
add_subdirectory(./sdl_image)
|
||||||
|
|
||||||
if (TOMATO_BREAKPAD)
|
if (TOMATO_BREAKPAD)
|
||||||
|
2
external/libqoirdo/CMakeLists.txt
vendored
2
external/libqoirdo/CMakeLists.txt
vendored
@ -15,6 +15,8 @@ add_library(qoirdo
|
|||||||
|
|
||||||
target_compile_features(qoirdo PUBLIC cxx_std_11)
|
target_compile_features(qoirdo PUBLIC cxx_std_11)
|
||||||
|
|
||||||
|
target_include_directories(qoirdo SYSTEM INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}")
|
||||||
|
|
||||||
#if (NOT MSVC)
|
#if (NOT MSVC)
|
||||||
# target_link_libraries(rdopng m pthread)
|
# target_link_libraries(rdopng m pthread)
|
||||||
#endif()
|
#endif()
|
||||||
|
@ -208,6 +208,7 @@ target_link_libraries(tomato PUBLIC
|
|||||||
WebP::webpdemux
|
WebP::webpdemux
|
||||||
WebP::libwebpmux # the f why (needed for anim encode)
|
WebP::libwebpmux # the f why (needed for anim encode)
|
||||||
qoi
|
qoi
|
||||||
|
qoirdo
|
||||||
SDL3_image::SDL3_image
|
SDL3_image::SDL3_image
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -473,12 +473,12 @@ void SendImagePopup::render(float time_delta) {
|
|||||||
|
|
||||||
if (compress) {
|
if (compress) {
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
ImGui::Combo("##compression_type", ¤t_compressor, "webp\0webp lossless\0jpeg\0png\0qoi\0");
|
ImGui::Combo("##compression_type", ¤t_compressor, "webp\0webp lossless\0jpeg\0png\0qoi\0qoi lossy\0");
|
||||||
|
|
||||||
ImGui::Indent();
|
ImGui::Indent();
|
||||||
// combo "webp""webp-lossless""png""jpg?"
|
// combo "webp""webp-lossless""png""jpg?"
|
||||||
// if lossy quality slider (1-100) default 80
|
// if lossy quality slider (1-100) default 80
|
||||||
if (current_compressor == 0 || current_compressor == 2) {
|
if (current_compressor == 0 || current_compressor == 2 || current_compressor == 5) {
|
||||||
const uint32_t qmin = 1;
|
const uint32_t qmin = 1;
|
||||||
const uint32_t qmax = 100;
|
const uint32_t qmax = 100;
|
||||||
recalc_size |= ImGui::SliderScalar("quality", ImGuiDataType_U32, &quality, &qmin, &qmax);
|
recalc_size |= ImGui::SliderScalar("quality", ImGuiDataType_U32, &quality, &qmin, &qmax);
|
||||||
@ -534,17 +534,22 @@ void SendImagePopup::render(float time_delta) {
|
|||||||
_on_send(new_data, ".webp");
|
_on_send(new_data, ".webp");
|
||||||
}
|
}
|
||||||
} else if (current_compressor == 2) {
|
} else if (current_compressor == 2) {
|
||||||
new_data = ImageEncoderSTBJpeg{}.encodeToMemoryRGBA(tmp_img, {{"quality", quality}});;
|
new_data = ImageEncoderSTBJpeg{}.encodeToMemoryRGBA(tmp_img, {{"quality", quality}});
|
||||||
if (!new_data.empty()) {
|
if (!new_data.empty()) {
|
||||||
_on_send(new_data, ".jpg");
|
_on_send(new_data, ".jpg");
|
||||||
}
|
}
|
||||||
} else if (current_compressor == 3) {
|
} else if (current_compressor == 3) {
|
||||||
new_data = ImageEncoderSTBPNG{}.encodeToMemoryRGBA(tmp_img, {{"png_compression_level", compression_level}});;
|
new_data = ImageEncoderSTBPNG{}.encodeToMemoryRGBA(tmp_img, {{"png_compression_level", compression_level}});
|
||||||
if (!new_data.empty()) {
|
if (!new_data.empty()) {
|
||||||
_on_send(new_data, ".png");
|
_on_send(new_data, ".png");
|
||||||
}
|
}
|
||||||
} else if (current_compressor == 4) {
|
} else if (current_compressor == 4) {
|
||||||
new_data = ImageEncoderQOI{}.encodeToMemoryRGBA(tmp_img, {});;
|
new_data = ImageEncoderQOI{}.encodeToMemoryRGBA(tmp_img, {});
|
||||||
|
if (!new_data.empty()) {
|
||||||
|
_on_send(new_data, ".qoi");
|
||||||
|
}
|
||||||
|
} else if (current_compressor == 5) {
|
||||||
|
new_data = ImageEncoderQOI{}.encodeToMemoryRGBA(tmp_img, {{"quality", quality}});
|
||||||
if (!new_data.empty()) {
|
if (!new_data.empty()) {
|
||||||
_on_send(new_data, ".qoi");
|
_on_send(new_data, ".qoi");
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
#include "./image_loader_qoi.hpp"
|
#include "./image_loader_qoi.hpp"
|
||||||
|
|
||||||
#include <qoi/qoi.h>
|
#include <qoi/qoi.h>
|
||||||
|
#include <qoirdo.hpp>
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include <mutex>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
@ -131,7 +133,7 @@ ImageLoaderQOI::ImageResult ImageLoaderQOI::loadFromMemoryRGBA(const uint8_t* da
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<uint8_t> ImageEncoderQOI::encodeToMemoryRGBA(const ImageResult& input_image, const std::map<std::string, float>&) {
|
std::vector<uint8_t> ImageEncoderQOI::encodeToMemoryRGBA(const ImageResult& input_image, const std::map<std::string, float>& extra_options) {
|
||||||
if (input_image.frames.empty()) {
|
if (input_image.frames.empty()) {
|
||||||
std::cerr << "IEQOI error: empty image\n";
|
std::cerr << "IEQOI error: empty image\n";
|
||||||
return {};
|
return {};
|
||||||
@ -143,34 +145,77 @@ std::vector<uint8_t> ImageEncoderQOI::encodeToMemoryRGBA(const ImageResult& inpu
|
|||||||
//png_compression_level = extra_options.at("png_compression_level");
|
//png_compression_level = extra_options.at("png_compression_level");
|
||||||
//}
|
//}
|
||||||
|
|
||||||
qoi_desc desc;
|
bool lossless = true;
|
||||||
desc.width = input_image.width;
|
int quality = 90;
|
||||||
desc.height = input_image.height;
|
if (extra_options.count("quality")) {
|
||||||
desc.channels = 4;
|
lossless = false;
|
||||||
desc.colorspace = QOI_SRGB; // TODO: decide
|
quality = extra_options.at("quality");
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<uint8_t> new_data;
|
std::vector<uint8_t> new_data;
|
||||||
for (const auto& frame : input_image.frames) {
|
if (lossless) {
|
||||||
int out_len {0};
|
qoi_desc desc;
|
||||||
uint8_t* enc_data = static_cast<uint8_t*>(qoi_encode(
|
desc.width = input_image.width;
|
||||||
frame.data.data(),
|
desc.height = input_image.height;
|
||||||
&desc,
|
desc.channels = 4;
|
||||||
&out_len
|
desc.colorspace = QOI_SRGB; // TODO: decide
|
||||||
));
|
|
||||||
|
|
||||||
if (enc_data == nullptr) {
|
for (const auto& frame : input_image.frames) {
|
||||||
std::cerr << "IEQOI error: qoi_encode failed!\n";
|
int out_len {0};
|
||||||
break;
|
uint8_t* enc_data = static_cast<uint8_t*>(qoi_encode(
|
||||||
|
frame.data.data(),
|
||||||
|
&desc,
|
||||||
|
&out_len
|
||||||
|
));
|
||||||
|
|
||||||
|
if (enc_data == nullptr) {
|
||||||
|
std::cerr << "IEQOI error: qoi_encode failed!\n";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// qoi_pipe like animation support. simple concatination of images
|
||||||
|
if (new_data.empty()) {
|
||||||
|
new_data = std::vector<uint8_t>(enc_data, enc_data+out_len);
|
||||||
|
} else {
|
||||||
|
new_data.insert(new_data.cend(), enc_data, enc_data+out_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(enc_data); // TODO: a streaming encoder would be better
|
||||||
|
}
|
||||||
|
} else { // rdo
|
||||||
|
// current rdo is not thread safe
|
||||||
|
static std::mutex rdo_mutex{};
|
||||||
|
std::lock_guard lg{rdo_mutex};
|
||||||
|
init_qoi_rdo();
|
||||||
|
|
||||||
|
// TODO: merge with qoi?
|
||||||
|
qoi_rdo_desc desc;
|
||||||
|
desc.width = input_image.width;
|
||||||
|
desc.height = input_image.height;
|
||||||
|
desc.channels = 4;
|
||||||
|
desc.colorspace = QOI_SRGB; // TODO: decide
|
||||||
|
|
||||||
|
for (const auto& frame : input_image.frames) {
|
||||||
|
auto enc_data = encode_qoi_rdo_simple(
|
||||||
|
frame.data.data(),
|
||||||
|
desc,
|
||||||
|
quality
|
||||||
|
);
|
||||||
|
|
||||||
|
if (enc_data.empty()) {
|
||||||
|
std::cerr << "IEQOI error: encode_qoi_rdo_simple failed!\n";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// qoi_pipe like animation support. simple concatination of images
|
||||||
|
if (new_data.empty()) {
|
||||||
|
new_data = enc_data;
|
||||||
|
} else {
|
||||||
|
new_data.insert(new_data.cend(), enc_data.cbegin(), enc_data.cend());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// qoi_pipe like animation support. simple concatination of images
|
quit_qoi_rdo();
|
||||||
if (new_data.empty()) {
|
|
||||||
new_data = std::vector<uint8_t>(enc_data, enc_data+out_len);
|
|
||||||
} else {
|
|
||||||
new_data.insert(new_data.cend(), enc_data, enc_data+out_len);
|
|
||||||
}
|
|
||||||
|
|
||||||
free(enc_data); // TODO: a streaming encoder would be better
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return new_data;
|
return new_data;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user