Working on better support for Windows clipboard

This commit is contained in:
Yousef Khadadeh 2026-01-12 11:27:41 +03:00
parent 340e694bdc
commit afaf43823c
5 changed files with 90 additions and 4 deletions

3
.gitmodules vendored
View file

@ -1,3 +1,6 @@
[submodule "deps/datachannel-wasm"]
path = deps/datachannel-wasm
url = https://github.com/paullouisageneau/datachannel-wasm.git
[submodule "deps/clip"]
path = deps/clip
url = https://github.com/dacap/clip.git

View file

@ -314,6 +314,12 @@ target_link_libraries(infinipaint zstd::libzstd_static)
if((NOT EMSCRIPTEN) AND WIN32)
target_link_libraries(infinipaint dwrite)
# Clip library for retrieving images from windows clipboard
set(CLIP_EXAMPLES OFF CACHE BOOL "Compile clip examples")
set(CLIP_TESTS OFF CACHE BOOL "Compile clip tests")
set(CLIP_ENABLE_IMAGE ON CACHE BOOL "Compile with image clipboard support")
add_subdirectory(deps/clip)
target_link_libraries(infinipaint clip)
endif()
if(EMSCRIPTEN)

View file

@ -0,0 +1,20 @@
Copyright (c) 2015-2025 David Capello
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

1
deps/clip vendored Submodule

@ -0,0 +1 @@
Subproject commit 4e878e1392dc379a55e5b63de2c822e8f2b6aa98

View file

@ -5,6 +5,14 @@
#include <optional>
#include <Helpers/Logger.hpp>
#ifdef _WIN32_
#include <include/core/SkStream.h>
#include <include/encode/SkPngEncoder.h>
#include "../deps/clip/clip.h"
#endif
#ifdef __EMSCRIPTEN__
#include <EmscriptenHelpers/emscripten_browser_clipboard.h>
@ -148,17 +156,65 @@ void InputManager::get_clipboard_image_data_SDL(const std::function<void(std::st
validMimetypes.emplace("image/jpeg");
validMimetypes.emplace("image/svg+xml");
validMimetypes.emplace("image/webp");
#ifdef _WIN32
validMimetypes.emplace("image/bmp");
#endif
}
size_t mimeTypeSize;
char** mimeTypes = SDL_GetClipboardMimeTypes(&mimeTypeSize);
if(mimeTypes) {
for(size_t i = 0; i < mimeTypeSize; i++) {
if(validMimetypes.contains(mimeTypes[i])) {
size_t clipboardDataSize;
void* clipboardData = SDL_GetClipboardData(mimeTypes[i], &clipboardDataSize);
callback(std::string_view(static_cast<char*>(clipboardData), clipboardDataSize));
SDL_free(clipboardData);
if(std::string(mimeTypes[i]) == "image/bmp") {
#ifdef _WIN32_
if(!clip::has(clip::image_format())) {
Logger::get().log("INFO", "[InputManager::get_clipboard_image_data_SDL] Clipboard doesn't contain an image");
return;
}
clip::image img;
if(!clip::get_image(img)) {
Logger::get().log("INFO", "[InputManager::get_clipboard_image_data_SDL] Error getting image from clipboard");
return;
}
clip::image_spec spec = img.spec();
if(spec.bits_per_pixel != 8) {
Logger::get().log("INFO", "[InputManager::get_clipboard_image_data_SDL] Clipboard doesn't use 8 bits per pixel");
return;
}
char* rawImageData = img.data();
std::vector<uint8_t> rgbaImageData(spec.width * spec.height * 4);
for(size_t y = 0; y < spec.height; y++) {
for(size_t x = 0; x < spec.width; x++) {
size_t rawDataIndex = x + y * spec.bytes_per_row;
size_t rgbaDataIndex = x + y * spec.height;
unsigned long rawDataAtIndex = *reinterpret_cast<unsigned long*>(rawImageData + rawDataIndex);
rgbaImageData[rgbaDataIndex + 0] = (rawDataAtIndex & spec.red_mask) >> spec.red_shift;
rgbaImageData[rgbaDataIndex + 1] = (rawDataAtIndex & spec.green_mask) >> spec.green_shift;
rgbaImageData[rgbaDataIndex + 2] = (rawDataAtIndex & spec.blue_mask) >> spec.blue_mask;
if(spec.alpha_mask == 0)
rgbaImageData[rgbaDataIndex + 3] = 255;
else
rgbaImageData[rgbaDataIndex + 3] = (rawDataAtIndex & spec.alpha_mask) >> spec.alpha_mask;
}
}
SkDynamicMemoryWStream out;
SkPngEncoder::Encode(&out, SkPixmap(SkImageInfo::Make(spec.width, spec.height, kRGBA_8888_SkColorType, kUnpremul_SkAlphaType), rgbaImageData.data(), rgbaImageData.size()), {});
out.flush();
std::vector<uint8_t> result = out.detachAsVector();
callback(std::string_view(reinterpret_cast<char*>(result.data()), result.size()));
#endif
}
else {
size_t clipboardDataSize;
void* clipboardData = SDL_GetClipboardData(mimeTypes[i], &clipboardDataSize);
callback(std::string_view(static_cast<char*>(clipboardData), clipboardDataSize));
SDL_free(clipboardData);
}
return;
}
}