add image scaling to send image popup
Some checks failed
ContinuousDelivery / linux-ubuntu (push) Has been cancelled
ContinuousDelivery / android (map[ndk_abi:arm64-v8a vcpkg_toolkit:arm64-android-23]) (push) Has been cancelled
ContinuousDelivery / android (map[ndk_abi:armeabi-v7a vcpkg_toolkit:arm-neon-android-23]) (push) Has been cancelled
ContinuousDelivery / android (map[ndk_abi:x86_64 vcpkg_toolkit:x64-android-23]) (push) Has been cancelled
ContinuousDelivery / windows (windows-2022, ) (push) Has been cancelled
ContinuousDelivery / windows (windows-2022, asan) (push) Has been cancelled
ContinuousDelivery / dumpsyms (push) Has been cancelled
ContinuousDelivery / release (push) Has been cancelled
ContinuousIntegration / on ubuntu-24.04-arm (push) Has been cancelled
ContinuousIntegration / asan on ubuntu-24.04-arm (push) Has been cancelled
ContinuousIntegration / on ubuntu-latest (push) Has been cancelled
ContinuousIntegration / asan on ubuntu-latest (push) Has been cancelled
ContinuousIntegration / android (map[ndk_abi:arm64-v8a vcpkg_toolkit:arm64-android-23]) (push) Has been cancelled
ContinuousIntegration / android (map[ndk_abi:armeabi-v7a vcpkg_toolkit:arm-neon-android-23]) (push) Has been cancelled
ContinuousIntegration / android (map[ndk_abi:x86_64 vcpkg_toolkit:x64-android-23]) (push) Has been cancelled
ContinuousIntegration / macos (push) Has been cancelled
ContinuousIntegration / windows (push) Has been cancelled
Some checks failed
ContinuousDelivery / linux-ubuntu (push) Has been cancelled
ContinuousDelivery / android (map[ndk_abi:arm64-v8a vcpkg_toolkit:arm64-android-23]) (push) Has been cancelled
ContinuousDelivery / android (map[ndk_abi:armeabi-v7a vcpkg_toolkit:arm-neon-android-23]) (push) Has been cancelled
ContinuousDelivery / android (map[ndk_abi:x86_64 vcpkg_toolkit:x64-android-23]) (push) Has been cancelled
ContinuousDelivery / windows (windows-2022, ) (push) Has been cancelled
ContinuousDelivery / windows (windows-2022, asan) (push) Has been cancelled
ContinuousDelivery / dumpsyms (push) Has been cancelled
ContinuousDelivery / release (push) Has been cancelled
ContinuousIntegration / on ubuntu-24.04-arm (push) Has been cancelled
ContinuousIntegration / asan on ubuntu-24.04-arm (push) Has been cancelled
ContinuousIntegration / on ubuntu-latest (push) Has been cancelled
ContinuousIntegration / asan on ubuntu-latest (push) Has been cancelled
ContinuousIntegration / android (map[ndk_abi:arm64-v8a vcpkg_toolkit:arm64-android-23]) (push) Has been cancelled
ContinuousIntegration / android (map[ndk_abi:armeabi-v7a vcpkg_toolkit:arm-neon-android-23]) (push) Has been cancelled
ContinuousIntegration / android (map[ndk_abi:x86_64 vcpkg_toolkit:x64-android-23]) (push) Has been cancelled
ContinuousIntegration / macos (push) Has been cancelled
ContinuousIntegration / windows (push) Has been cancelled
This commit is contained in:
@@ -13,6 +13,7 @@
|
|||||||
|
|
||||||
#include <imgui.h>
|
#include <imgui.h>
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
||||||
SendImagePopup::SendImagePopup(TextureUploaderI& tu) : _tu(tu) {
|
SendImagePopup::SendImagePopup(TextureUploaderI& tu) : _tu(tu) {
|
||||||
@@ -245,7 +246,7 @@ void SendImagePopup::render(float time_delta) {
|
|||||||
- (
|
- (
|
||||||
ImGui::GetWindowContentRegionMin().y
|
ImGui::GetWindowContentRegionMin().y
|
||||||
+ TEXT_BASE_HEIGHT*(2-1) // row of buttons (-1 bc fh inclues fontsize)
|
+ TEXT_BASE_HEIGHT*(2-1) // row of buttons (-1 bc fh inclues fontsize)
|
||||||
+ ImGui::GetFrameHeightWithSpacing()*4
|
+ ImGui::GetFrameHeightWithSpacing()*6
|
||||||
)
|
)
|
||||||
;
|
;
|
||||||
if (height > max_height) {
|
if (height > max_height) {
|
||||||
@@ -340,23 +341,22 @@ void SendImagePopup::render(float time_delta) {
|
|||||||
{ // 4 lines delimiting the crop result
|
{ // 4 lines delimiting the crop result
|
||||||
ImU32 line_color = 0xffffffff;
|
ImU32 line_color = 0xffffffff;
|
||||||
{ // calc color
|
{ // calc color
|
||||||
|
static constexpr auto f = [](float x) {
|
||||||
|
while (x < 0.f) {
|
||||||
|
x += 1.f;
|
||||||
|
}
|
||||||
|
|
||||||
|
x = std::fmod(x, 1.f); // fract()
|
||||||
|
|
||||||
|
if (x < 1.f/3) {
|
||||||
|
return x * 3;
|
||||||
|
} else if (x < 2.f/3) {
|
||||||
|
return (1 - (x - (1.f/3))) * 3 - 2;
|
||||||
|
} else {
|
||||||
|
return 0.f;
|
||||||
|
}
|
||||||
|
};
|
||||||
auto rgb = [](float x) -> ImVec4 {
|
auto rgb = [](float x) -> ImVec4 {
|
||||||
auto f = [](float x) {
|
|
||||||
while (x < 0.f) {
|
|
||||||
x += 1.f;
|
|
||||||
}
|
|
||||||
|
|
||||||
x = std::fmod(x, 1.f); // fract()
|
|
||||||
|
|
||||||
if (x < 1.f/3) {
|
|
||||||
return x * 3;
|
|
||||||
} else if (x < 2.f/3) {
|
|
||||||
return (1 - (x - (1.f/3))) * 3 - 2;
|
|
||||||
} else {
|
|
||||||
return 0.f;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
float red = f(x);
|
float red = f(x);
|
||||||
float green = f(x - (1.f/3));
|
float green = f(x - (1.f/3));
|
||||||
float blue = f(x - (2.f/3));
|
float blue = f(x - (2.f/3));
|
||||||
@@ -434,7 +434,7 @@ void SendImagePopup::render(float time_delta) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const bool cropped = crop_rect.x != 0 || crop_rect.y != 0 || crop_rect.w != original_image.width || crop_rect.h != original_image.height;
|
const bool cropped = crop_rect.x != 0 || crop_rect.y != 0 || crop_rect.w != int64_t(original_image.width) || crop_rect.h != int64_t(original_image.height);
|
||||||
if (cropping) {
|
if (cropping) {
|
||||||
if (ImGui::Button("done")) {
|
if (ImGui::Button("done")) {
|
||||||
cropping = false;
|
cropping = false;
|
||||||
@@ -445,7 +445,7 @@ void SendImagePopup::render(float time_delta) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
if (ImGui::Button("reset")) {
|
if (ImGui::Button("reset##crop")) {
|
||||||
crop_rect.x = 0;
|
crop_rect.x = 0;
|
||||||
crop_rect.y = 0;
|
crop_rect.y = 0;
|
||||||
crop_rect.w = original_image.width;
|
crop_rect.w = original_image.width;
|
||||||
@@ -455,6 +455,35 @@ void SendImagePopup::render(float time_delta) {
|
|||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
ImGui::Text("x:%d y:%d w:%d h:%d", crop_rect.x, crop_rect.y, crop_rect.w, crop_rect.h);
|
ImGui::Text("x:%d y:%d w:%d h:%d", crop_rect.x, crop_rect.y, crop_rect.w, crop_rect.h);
|
||||||
|
|
||||||
|
ImGui::TextUnformatted("scale");
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::Button("reset##scale")) {
|
||||||
|
scale_x = 1.f;
|
||||||
|
scale_y = 1.f;
|
||||||
|
compress = false; // feels nice
|
||||||
|
}
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::SetNextItemWidth(TEXT_BASE_HEIGHT*3);
|
||||||
|
if (ImGui::DragFloat("##scale x", &scale_x, 0.001f, 0.001f, 100.f) && scale_tie) {
|
||||||
|
scale_y = scale_x;
|
||||||
|
}
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::TextUnformatted("X");
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::SetNextItemWidth(TEXT_BASE_HEIGHT*3);
|
||||||
|
if (ImGui::DragFloat("##scale y", &scale_y, 0.001f, 0.001f, 100.f) && scale_tie) {
|
||||||
|
scale_x = scale_y;
|
||||||
|
}
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::Checkbox("tie", &scale_tie);
|
||||||
|
|
||||||
|
if (scale_x <= 0.f) { scale_x = 0.001f; }
|
||||||
|
if (scale_y <= 0.f) { scale_y = 0.001f; }
|
||||||
|
if (scale_x > 100.f) { scale_x = 100.f; }
|
||||||
|
if (scale_y > 100.f) { scale_y = 100.f; }
|
||||||
|
|
||||||
|
ImGui::Text("final size -> w:%d h:%d", (int)std::ceil(crop_rect.w*scale_x), (int)std::ceil(crop_rect.h*scale_y));
|
||||||
|
|
||||||
bool recalc_size = false;
|
bool recalc_size = false;
|
||||||
if (cropped) {
|
if (cropped) {
|
||||||
if (!compress) {
|
if (!compress) {
|
||||||
@@ -463,6 +492,13 @@ void SendImagePopup::render(float time_delta) {
|
|||||||
}
|
}
|
||||||
compress = true;
|
compress = true;
|
||||||
}
|
}
|
||||||
|
if (scale_x != 1.f || scale_y != 1.f) {
|
||||||
|
if (!compress) {
|
||||||
|
// looks like a change
|
||||||
|
recalc_size = true;
|
||||||
|
}
|
||||||
|
compress = true;
|
||||||
|
}
|
||||||
|
|
||||||
recalc_size |= ImGui::Checkbox("compress", &compress);
|
recalc_size |= ImGui::Checkbox("compress", &compress);
|
||||||
if (cropped && ImGui::IsItemHovered()) {
|
if (cropped && ImGui::IsItemHovered()) {
|
||||||
@@ -505,11 +541,10 @@ void SendImagePopup::render(float time_delta) {
|
|||||||
}
|
}
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
if (ImGui::Button("send ->", {-FLT_MIN, TEXT_BASE_HEIGHT*2})) {
|
if (ImGui::Button("send ->", {-FLT_MIN, TEXT_BASE_HEIGHT*2})) {
|
||||||
if (compress || cropped) {
|
if (compress || cropped || scale_x != 1.f || scale_y != 1.f) {
|
||||||
// TODO: copy bad
|
// TODO: copy bad
|
||||||
ImageLoaderI::ImageResult tmp_img;
|
ImageLoaderI::ImageResult tmp_img;
|
||||||
if (cropped) {
|
if (cropped) {
|
||||||
std::cout << "SIP: CROP!!!!!\n";
|
|
||||||
tmp_img = original_image.crop(
|
tmp_img = original_image.crop(
|
||||||
crop_rect.x,
|
crop_rect.x,
|
||||||
crop_rect.y,
|
crop_rect.y,
|
||||||
@@ -520,6 +555,15 @@ void SendImagePopup::render(float time_delta) {
|
|||||||
tmp_img = original_image;
|
tmp_img = original_image;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (scale_x != 1.f || scale_y != 1.f) {
|
||||||
|
tmp_img = tmp_img.scale(
|
||||||
|
(int)std::ceil(crop_rect.w*scale_x),
|
||||||
|
(int)std::ceil(crop_rect.h*scale_y)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
tmp_img = original_image;
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<uint8_t> new_data;
|
std::vector<uint8_t> new_data;
|
||||||
|
|
||||||
// HACK: generic list
|
// HACK: generic list
|
||||||
|
|||||||
@@ -36,6 +36,10 @@ struct SendImagePopup {
|
|||||||
bool dragging_last_frame_ul {false};
|
bool dragging_last_frame_ul {false};
|
||||||
bool dragging_last_frame_lr {false};
|
bool dragging_last_frame_lr {false};
|
||||||
|
|
||||||
|
float scale_x {1.f};
|
||||||
|
float scale_y {1.f};
|
||||||
|
bool scale_tie {true};
|
||||||
|
|
||||||
// texture to render (orig img)
|
// texture to render (orig img)
|
||||||
TextureEntry preview_image;
|
TextureEntry preview_image;
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
#include "./image_loader.hpp"
|
#include "./image_loader.hpp"
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
#include "./image_scaler.hpp"
|
||||||
|
|
||||||
ImageLoaderI::ImageResult ImageLoaderI::ImageResult::crop(int32_t c_x, int32_t c_y, int32_t c_w, int32_t c_h) const {
|
ImageLoaderI::ImageResult ImageLoaderI::ImageResult::crop(int32_t c_x, int32_t c_y, int32_t c_w, int32_t c_h) const {
|
||||||
// TODO: proper error handling
|
// TODO: proper error handling
|
||||||
@@ -30,3 +33,23 @@ ImageLoaderI::ImageResult ImageLoaderI::ImageResult::crop(int32_t c_x, int32_t c
|
|||||||
return new_image;
|
return new_image;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ImageLoaderI::ImageResult ImageLoaderI::ImageResult::scale(int32_t w, int32_t h) const {
|
||||||
|
assert(w > 0);
|
||||||
|
assert(h > 0);
|
||||||
|
|
||||||
|
ImageLoaderI::ImageResult new_image;
|
||||||
|
new_image.width = w;
|
||||||
|
new_image.height = h;
|
||||||
|
new_image.file_ext = file_ext;
|
||||||
|
|
||||||
|
for (const auto& input_frame : frames) {
|
||||||
|
auto& new_frame = new_image.frames.emplace_back();
|
||||||
|
new_frame.ms = input_frame.ms;
|
||||||
|
|
||||||
|
new_frame.data.resize(w*h*4);
|
||||||
|
|
||||||
|
image_scale(new_frame.data.data(), w, h, const_cast<uint8_t*>(input_frame.data.data()), width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new_image;
|
||||||
|
}
|
||||||
|
|||||||
@@ -28,7 +28,8 @@ struct ImageLoaderI {
|
|||||||
// only positive values are valid
|
// only positive values are valid
|
||||||
ImageResult crop(int32_t c_x, int32_t c_y, int32_t c_w, int32_t c_h) const;
|
ImageResult crop(int32_t c_x, int32_t c_y, int32_t c_w, int32_t c_h) const;
|
||||||
|
|
||||||
// TODO: scale
|
// only values > 0 are valid
|
||||||
|
ImageResult scale(int32_t w, int32_t h) const;
|
||||||
};
|
};
|
||||||
virtual ImageResult loadFromMemoryRGBA(const uint8_t* data, uint64_t data_size) = 0;
|
virtual ImageResult loadFromMemoryRGBA(const uint8_t* data, uint64_t data_size) = 0;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ struct ColorCanvas8888 {
|
|||||||
};
|
};
|
||||||
|
|
||||||
template<typename ColorCanvas, typename ColorTmp>
|
template<typename ColorCanvas, typename ColorTmp>
|
||||||
void image_scale(ColorCanvas& dst, const int dst_w, const int dst_h, const ColorCanvas& src, const int src_w, const int src_h) {
|
constexpr void image_scale(ColorCanvas& dst, const int dst_w, const int dst_h, const ColorCanvas& src, const int src_w, const int src_h) {
|
||||||
// Box sampling - Imagine projecting the new, smaller pixels onto the larger source, covering multiple pixel.
|
// Box sampling - Imagine projecting the new, smaller pixels onto the larger source, covering multiple pixel.
|
||||||
for (int y = 0; y < dst_h; y++) {
|
for (int y = 0; y < dst_h; y++) {
|
||||||
for (int x = 0; x < dst_w; x++) {
|
for (int x = 0; x < dst_w; x++) {
|
||||||
@@ -109,7 +109,33 @@ void image_scale(ColorCanvas& dst, const int dst_w, const int dst_h, const Color
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool image_scale(uint8_t* dst, const int dst_w, const int dst_h, uint8_t* src, const int src_w, const int src_h) {
|
||||||
|
if (dst == nullptr || src == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (dst_w == src_w && dst_h == src_h) {
|
||||||
|
assert(false && "fix me !");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ColorCanvas8888 dst_c{dst};
|
||||||
|
const ColorCanvas8888 src_c{src};
|
||||||
|
|
||||||
|
image_scale<ColorCanvas8888, ColorFloat4>(
|
||||||
|
dst_c,
|
||||||
|
dst_w, dst_h,
|
||||||
|
src_c,
|
||||||
|
src_w, src_h
|
||||||
|
);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool image_scale(SDL_Surface* dst, SDL_Surface* src) {
|
bool image_scale(SDL_Surface* dst, SDL_Surface* src) {
|
||||||
|
if (dst == nullptr || src == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (dst->format != src->format) {
|
if (dst->format != src->format) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <SDL3/SDL.h>
|
#include <SDL3/SDL.h>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
bool image_scale(uint8_t* dst, const int dst_w, const int dst_h, uint8_t* src, const int src_w, const int src_h);
|
||||||
|
|
||||||
bool image_scale(SDL_Surface* dst, SDL_Surface* src);
|
bool image_scale(SDL_Surface* dst, SDL_Surface* src);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user