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

This commit is contained in:
Green Sky
2025-11-05 18:53:07 +01:00
parent e8a15a58dd
commit 1547999ec0
6 changed files with 124 additions and 23 deletions

View File

@@ -13,6 +13,7 @@
#include <imgui.h>
#include <cstdint>
#include <cmath>
SendImagePopup::SendImagePopup(TextureUploaderI& tu) : _tu(tu) {
@@ -245,7 +246,7 @@ void SendImagePopup::render(float time_delta) {
- (
ImGui::GetWindowContentRegionMin().y
+ TEXT_BASE_HEIGHT*(2-1) // row of buttons (-1 bc fh inclues fontsize)
+ ImGui::GetFrameHeightWithSpacing()*4
+ ImGui::GetFrameHeightWithSpacing()*6
)
;
if (height > max_height) {
@@ -340,23 +341,22 @@ void SendImagePopup::render(float time_delta) {
{ // 4 lines delimiting the crop result
ImU32 line_color = 0xffffffff;
{ // 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 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 green = f(x - (1.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 (ImGui::Button("done")) {
cropping = false;
@@ -445,7 +445,7 @@ void SendImagePopup::render(float time_delta) {
}
}
ImGui::SameLine();
if (ImGui::Button("reset")) {
if (ImGui::Button("reset##crop")) {
crop_rect.x = 0;
crop_rect.y = 0;
crop_rect.w = original_image.width;
@@ -455,6 +455,35 @@ void SendImagePopup::render(float time_delta) {
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::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;
if (cropped) {
if (!compress) {
@@ -463,6 +492,13 @@ void SendImagePopup::render(float time_delta) {
}
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);
if (cropped && ImGui::IsItemHovered()) {
@@ -505,11 +541,10 @@ void SendImagePopup::render(float time_delta) {
}
ImGui::SameLine();
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
ImageLoaderI::ImageResult tmp_img;
if (cropped) {
std::cout << "SIP: CROP!!!!!\n";
tmp_img = original_image.crop(
crop_rect.x,
crop_rect.y,
@@ -520,6 +555,15 @@ void SendImagePopup::render(float time_delta) {
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;
// HACK: generic list

View File

@@ -36,6 +36,10 @@ struct SendImagePopup {
bool dragging_last_frame_ul {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)
TextureEntry preview_image;

View File

@@ -1,6 +1,9 @@
#include "./image_loader.hpp"
#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 {
// TODO: proper error handling
@@ -30,3 +33,23 @@ ImageLoaderI::ImageResult ImageLoaderI::ImageResult::crop(int32_t c_x, int32_t c
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;
}

View File

@@ -28,7 +28,8 @@ struct ImageLoaderI {
// only positive values are valid
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;
};

View File

@@ -67,7 +67,7 @@ struct ColorCanvas8888 {
};
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.
for (int y = 0; y < dst_h; y++) {
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) {
if (dst == nullptr || src == nullptr) {
return false;
}
if (dst->format != src->format) {
return false;
}

View File

@@ -1,6 +1,9 @@
#pragma once
#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);