From db8418159ea20b0bbec08871c24f57cb8326a44c Mon Sep 17 00:00:00 2001 From: Yousef Khadadeh Date: Mon, 12 Jan 2026 15:02:55 +0300 Subject: [PATCH] Windows clipboard for images improved --- docs/BUILDING.md | 6 ++- src/InputManager.cpp | 99 +++++++++++++++++++++++++++----------------- 2 files changed, 67 insertions(+), 38 deletions(-) diff --git a/docs/BUILDING.md b/docs/BUILDING.md index faa4280..875e7cb 100644 --- a/docs/BUILDING.md +++ b/docs/BUILDING.md @@ -32,7 +32,11 @@ cpack -G DragNDrop ## Windows The windows version of this program is built on Visual Studio 2022's compiler. -After cloning the repository, `cd` into the repo, then run: +After cloning the repository, `cd` into the repo, then update the git submodules to get the `clip` library: +``` +git submodule update --init --recursive +``` +Then run: ``` .\conan\export_libs.bat conan install . --build=missing -pr=conan/profiles/win-x86_64 diff --git a/src/InputManager.cpp b/src/InputManager.cpp index adfdd04..69cc195 100644 --- a/src/InputManager.cpp +++ b/src/InputManager.cpp @@ -147,6 +147,26 @@ std::string InputManager::get_clipboard_str_SDL() { return toRet; } +#ifdef _WIN32 +// From clip library example, useful for debugging +void print_clip_image_spec(const clip::image_spec& spec) { + std::cout << "Image in clipboard " + << spec.width << "x" << spec.height + << " (" << spec.bits_per_pixel << "bpp)\n" + << "Format:" << "\n" + << std::hex + << " Red mask: " << spec.red_mask << "\n" + << " Green mask: " << spec.green_mask << "\n" + << " Blue mask: " << spec.blue_mask << "\n" + << " Alpha mask: " << spec.alpha_mask << "\n" + << std::dec + << " Red shift: " << spec.red_shift << "\n" + << " Green shift: " << spec.green_shift << "\n" + << " Blue shift: " << spec.blue_shift << "\n" + << " Alpha shift: " << spec.alpha_shift << "\n"; +} +#endif + void InputManager::get_clipboard_image_data_SDL(const std::function& callback) { #ifndef __EMSCRIPTEN__ static std::unordered_set validMimetypes; @@ -167,46 +187,51 @@ void InputManager::get_clipboard_image_data_SDL(const std::function 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(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; + std::vector result; + try { + if(!clip::has(clip::image_format())) + throw std::runtime_error("Clipboard doesn't contain an image"); + + clip::image img; + if(!clip::get_image(img)) + throw std::runtime_error("Error getting image from clipboard"); + + clip::image_spec spec = img.spec(); + + SDL_PixelFormat pFormat = SDL_GetPixelFormatForMasks(spec.bits_per_pixel, spec.red_mask, spec.green_mask, spec.blue_mask, spec.alpha_mask); + if(pFormat != SDL_PIXELFORMAT_UNKNOWN) { + SDL_Surface* surfOriginal = SDL_CreateSurfaceFrom(spec.width, spec.height, pFormat, img.data(), spec.bytes_per_row); + if(surfOriginal) { + SDL_LockSurface(surfOriginal); + SDL_Surface* cSurf = SDL_ConvertSurface(surfOriginal, SDL_PIXELFORMAT_RGBA32); + SDL_UnlockSurface(surfOriginal); + SDL_DestroySurface(surfOriginal); + if(cSurf) { + SDL_LockSurface(cSurf); + SkDynamicMemoryWStream out; + SkPngEncoder::Encode(&out, SkPixmap(SkImageInfo::Make(cSurf->w, cSurf->h, kRGBA_8888_SkColorType, kUnpremul_SkAlphaType), cSurf->pixels, cSurf->pitch), {}); + out.flush(); + SDL_UnlockSurface(cSurf); + SDL_DestroySurface(cSurf); + result = out.detachAsVector(); + } + else + throw std::runtime_error("Bitmap could not be converted to new format"); + } else - rgbaImageData[rgbaDataIndex + 3] = (rawDataAtIndex & spec.alpha_mask) >> spec.alpha_mask; + throw std::runtime_error("Bitmap could not be read into surface"); } + else + throw std::runtime_error("Bitmap format is unsupported"); } - - 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 result = out.detachAsVector(); - callback(std::string_view(reinterpret_cast(result.data()), result.size())); + catch(const std::runtime_error& e) { + Logger::get().log("INFO", std::string("[InputManager::get_clipboard_image_data_SDL] Error thrown: ") + e.what()); + } + catch(...) { + Logger::get().log("INFO", "[InputManager::get_clipboard_image_data_SDL] Unknown error thrown"); + } + if(!result.empty()) + callback(std::string_view((char*)(result.data()), result.size())); // This part of the code should throw errors #endif } else {