From eba49fcaca40e25b0ee00d1f065ceaa31f58a73a Mon Sep 17 00:00:00 2001 From: iProgramInCpp Date: Sat, 11 May 2024 21:24:06 +0300 Subject: [PATCH] * Force alpha to 255 when pasting copied images. Fixes #13. (ish) * Add USE_DEBUG_PRINTS to allow debug prints to show on release mode. --- src/discord/Frontend.hpp | 2 +- src/discord/Util.cpp | 2 +- src/discord/Util.hpp | 6 ++- src/windows/Frontend_Win32.cpp | 2 +- src/windows/Frontend_Win32.hpp | 2 +- src/windows/ImageLoader.cpp | 11 +++-- src/windows/ImageLoader.hpp | 2 +- src/windows/Main.cpp | 83 ++++++++++++++++++++-------------- src/windows/WinUtils.cpp | 36 +++++++++++++++ src/windows/WinUtils.hpp | 3 +- 10 files changed, 104 insertions(+), 45 deletions(-) diff --git a/src/discord/Frontend.hpp b/src/discord/Frontend.hpp index ab08158..c568440 100644 --- a/src/discord/Frontend.hpp +++ b/src/discord/Frontend.hpp @@ -92,7 +92,7 @@ class Frontend virtual std::string GetFormatTimeShorterText() = 0; // Debugging -#ifdef _DEBUG +#ifdef USE_DEBUG_PRINTS virtual void DebugPrint(const char* fmt, va_list vl) = 0; #endif }; diff --git a/src/discord/Util.cpp b/src/discord/Util.cpp index 5724de0..00ddc2b 100644 --- a/src/discord/Util.cpp +++ b/src/discord/Util.cpp @@ -451,7 +451,7 @@ std::string GetAppVersionString() return "V1.01"; } -#ifdef _DEBUG +#ifdef USE_DEBUG_PRINTS void DbgPrintF(const char* fmt, ...) { va_list vl; diff --git a/src/discord/Util.hpp b/src/discord/Util.hpp index de9651b..58cf055 100644 --- a/src/discord/Util.hpp +++ b/src/discord/Util.hpp @@ -4,6 +4,10 @@ #include #include "Snowflake.hpp" +#ifdef _DEBUG +#define USE_DEBUG_PRINTS +#endif + std::string GetBasePath(); std::string GetCachePath(); void SetBasePath(const std::string& appDataPath); @@ -40,7 +44,7 @@ float CompareFuzzy(const std::string& item, const char* query); // returns a "cl float GetAppVersion(); std::string GetAppVersionString(); -#ifdef _DEBUG +#ifdef USE_DEBUG_PRINTS void DbgPrintF(const char* fmt, ...); #else #define DbgPrintF(...) diff --git a/src/windows/Frontend_Win32.cpp b/src/windows/Frontend_Win32.cpp index 28f7acf..c3cdfe7 100644 --- a/src/windows/Frontend_Win32.cpp +++ b/src/windows/Frontend_Win32.cpp @@ -297,7 +297,7 @@ void Frontend_Win32::GetIdentifyProperties(nlohmann::json& j) j["system_locale"] = "en-US"; } -#ifdef _DEBUG +#ifdef USE_DEBUG_PRINTS void DbgPrintWV(const char* fmt, va_list vl) { diff --git a/src/windows/Frontend_Win32.hpp b/src/windows/Frontend_Win32.hpp index 4add01c..e4cdd98 100644 --- a/src/windows/Frontend_Win32.hpp +++ b/src/windows/Frontend_Win32.hpp @@ -63,7 +63,7 @@ class Frontend_Win32 : public Frontend std::string GetFormatTimeShortText() override; std::string GetFormatTimeShorterText() override; -#ifdef _DEBUG +#ifdef USE_DEBUG_PRINTS void DebugPrint(const char* fmt, va_list vl) override; #endif }; diff --git a/src/windows/ImageLoader.cpp b/src/windows/ImageLoader.cpp index e855926..a948d42 100644 --- a/src/windows/ImageLoader.cpp +++ b/src/windows/ImageLoader.cpp @@ -154,10 +154,13 @@ static void ConvertToPNGWriteFunc(void* context, void* data, int size) memcpy(vec->data() + old_size, data, size); } -bool ImageLoader::ConvertToPNG(std::vector* outData, void* pBits, int width, int height, int widthBytes, int bpp) +bool ImageLoader::ConvertToPNG(std::vector* outData, void* pBits, int width, int height, int widthBytes, int bpp, bool forceOpaque, bool flipVerticallyWhenSaving) { uint32_t* interm_data = new uint32_t[width * height]; uint8_t* bits_b = (uint8_t*) pBits; + uint32_t auxBits = 0; + if (forceOpaque) + auxBits = 255U << 24; switch (bpp) { case 32: { @@ -175,7 +178,7 @@ bool ImageLoader::ConvertToPNG(std::vector* outData, void* pBits, int w uint8_t tmp = u.b[0]; u.b[0] = u.b[2]; u.b[2] = tmp; - *(write_ptr++) = u.x; + *(write_ptr++) = u.x | auxBits; } } break; @@ -186,7 +189,7 @@ bool ImageLoader::ConvertToPNG(std::vector* outData, void* pBits, int w for (int y = 0; y < height; y++) { uint8_t* read_ptr = (uint8_t*)(bits_b + widthBytes * y); for (int x = 0; x < width; x++) { - uint32_t rd = 255 << 24; // full alpha + uint32_t rd = 255U << 24; // full alpha rd |= read_ptr[2]; rd |= read_ptr[1] << 8; rd |= read_ptr[0] << 16; @@ -203,6 +206,8 @@ bool ImageLoader::ConvertToPNG(std::vector* outData, void* pBits, int w return false; } + stbi_flip_vertically_on_write(flipVerticallyWhenSaving); + if (!stbi_write_png_to_func(ConvertToPNGWriteFunc, (void*) outData, width, height, 4, (const void*) interm_data, width * sizeof(uint32_t))) { delete[] interm_data; return false; diff --git a/src/windows/ImageLoader.hpp b/src/windows/ImageLoader.hpp index fd0394d..f979a70 100644 --- a/src/windows/ImageLoader.hpp +++ b/src/windows/ImageLoader.hpp @@ -8,6 +8,6 @@ class ImageLoader { public: static HBITMAP ConvertToBitmap(const uint8_t* pData, size_t size, int width = 0, int height = 0); - static bool ConvertToPNG(std::vector* outData, void* pBits, int width, int height, int widthBytes, int bpp); + static bool ConvertToPNG(std::vector* outData, void* pBits, int width, int height, int widthBytes, int bpp, bool forceOpaque, bool flipVerticallyWhenSaving); }; diff --git a/src/windows/Main.cpp b/src/windows/Main.cpp index 5c69720..3126e16 100644 --- a/src/windows/Main.cpp +++ b/src/windows/Main.cpp @@ -432,22 +432,55 @@ BOOL HandleCommand(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) HDC hdc = NULL; BYTE* pBytes = nullptr; LPTSTR fileName = nullptr; - BITMAP bm; - BITMAPINFO bmi; std::vector data; bool isClipboardClosed = false; + bool hadToUseLegacyBitmap = false; + int width = 0, height = 0, stride = 0, bpp = 0; - hbm = (HBITMAP) GetClipboardData (CF_BITMAP); - if (!hbm) + HANDLE hbmi = GetClipboardData(CF_DIB); + if (hbmi) { - CloseClipboard(); + DbgPrintW("Using CF_DIB to fetch image from clipboard"); + PBITMAPINFO bmi = (PBITMAPINFO) GlobalLock(hbmi); - // No bitmap, forward to the edit control if selected - HWND hFocus = GetFocus(); - if (hFocus == g_pMessageEditor->m_edit_hwnd) - SendMessage(hFocus, WM_PASTE, 0, 0); + width = bmi->bmiHeader.biWidth; + height = bmi->bmiHeader.biHeight; + bpp = bmi->bmiHeader.biBitCount; + stride = ((((width * bpp) + 31) & ~31) >> 3); - return FALSE; + int sz = stride * height; + pBytes = new BYTE[sz]; + memcpy(pBytes, bmi + 1, sz); + + GlobalUnlock(hbmi); + } + else + { + // try legacy CF_BITMAP + DbgPrintW("Using legacy CF_BITMAP"); + HBITMAP hbm = (HBITMAP) GetClipboardData(CF_BITMAP); + hadToUseLegacyBitmap = true; + + if (!hbm) + { + CloseClipboard(); + + // No bitmap, forward to the edit control if selected + HWND hFocus = GetFocus(); + if (hFocus == g_pMessageEditor->m_edit_hwnd) + SendMessage(hFocus, WM_PASTE, 0, 0); + + return FALSE; + } + + HDC hdc = GetDC(hWnd); + bool res = GetDataFromBitmap(hdc, hbm, pBytes, width, height, bpp); + ReleaseDC(hWnd, hdc); + + if (!res) + goto _fail; + + stride = ((((width * bpp) + 31) & ~31) >> 3); } Channel* pChan = GetDiscordInstance()->GetCurrentChannel(); @@ -462,32 +495,12 @@ BOOL HandleCommand(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) goto _fail; } - // Man what the hell - hdc = GetDC(hWnd); - - ZeroMemory(&bm, sizeof bm); - if (!GetObject(hbm, sizeof bm, &bm)) { - DbgPrintW("Cannot obtain pointer to bitmap!"); - goto _fail; - } - - ZeroMemory(&bmi, sizeof bmi); - bmi.bmiHeader.biSize = sizeof bmi.bmiHeader; - bmi.bmiHeader.biWidth = bm.bmWidth; - bmi.bmiHeader.biHeight = -bm.bmHeight; - bmi.bmiHeader.biPlanes = 1; - bmi.bmiHeader.biBitCount = bm.bmBitsPixel; - bmi.bmiHeader.biCompression = BI_RGB; - bmi.bmiHeader.biSizeImage = 0; - - pBytes = new BYTE[bm.bmWidth * bm.bmHeight * (bm.bmBitsPixel / 8)]; - - if (!GetDIBits(hdc, hbm, 0, bm.bmHeight, pBytes, &bmi, DIB_RGB_COLORS)) { - DbgPrintW("Error, can't get DI bits for bitmap!"); - goto _fail; - } + // TODO: Don't always force alpha when pasting from CF_DIB or CF_BITMAP. + // I know this sucks, but I've tried a lot of things... - if (!ImageLoader::ConvertToPNG(&data, pBytes, bm.bmWidth, bm.bmHeight, bm.bmWidth * sizeof(uint32_t), 32)) { + // have to force alpha always + // have to flip vertically if !hadToUseLegacyBitmap + if (!ImageLoader::ConvertToPNG(&data, pBytes, width, height, stride, 32, true, !hadToUseLegacyBitmap)) { DbgPrintW("Cannot convert to PNG!"); goto _fail; } diff --git a/src/windows/WinUtils.cpp b/src/windows/WinUtils.cpp index c792b0f..56abda4 100644 --- a/src/windows/WinUtils.cpp +++ b/src/windows/WinUtils.cpp @@ -841,3 +841,39 @@ void DrawErrorBox(HDC hdc, RECT rect) int y = rect.top + (rect.bottom - rect.top - smcxsmicon) / 2; DrawIconEx(hdc, x, y, g_ImgErrorIcon, smcxsmicon, smcxsmicon, 0, NULL, DI_COMPAT | DI_NORMAL); } + +bool GetDataFromBitmap(HDC hdc, HBITMAP hbm, BYTE*& pBytes, int& width, int& height, int& bpp) +{ + // Man what the hell + BITMAP bm; + BITMAPINFO bmi; + + ZeroMemory(&bm, sizeof bm); + if (!GetObject(hbm, sizeof bm, &bm)) { + DbgPrintW("Cannot obtain pointer to bitmap!"); + return false; + } + + width = bm.bmWidth; + height = bm.bmHeight; + bpp = bm.bmBitsPixel; + + ZeroMemory(&bmi, sizeof bmi); + bmi.bmiHeader.biSize = sizeof bmi.bmiHeader; + bmi.bmiHeader.biWidth = bm.bmWidth; + bmi.bmiHeader.biHeight = -bm.bmHeight; + bmi.bmiHeader.biPlanes = 1; + bmi.bmiHeader.biBitCount = bm.bmBitsPixel; + bmi.bmiHeader.biCompression = BI_RGB; + bmi.bmiHeader.biSizeImage = 0; + + pBytes = new BYTE[bm.bmWidth * bm.bmHeight * (bm.bmBitsPixel / 8)]; + + if (!GetDIBits(hdc, hbm, 0, bm.bmHeight, pBytes, &bmi, DIB_RGB_COLORS)) { + DbgPrintW("Error, can't get DI bits for bitmap!"); + delete[] pBytes; + return false; + } + + return true; +} diff --git a/src/windows/WinUtils.hpp b/src/windows/WinUtils.hpp index cc0182f..8eed2f7 100644 --- a/src/windows/WinUtils.hpp +++ b/src/windows/WinUtils.hpp @@ -73,8 +73,9 @@ void DrawMentionStatus(HDC hdc, int x, int y, int mentionCount); void DrawActivityStatus(HDC hdc, int x, int y, eActiveStatus status); void DrawLoadingBox(HDC hdc, RECT rect); void DrawErrorBox(HDC hdc, RECT rect); +bool GetDataFromBitmap(HDC hdc, HBITMAP hbm, BYTE*& pBytes, int& width, int& height, int& bpp); -#ifdef _DEBUG +#ifdef USE_DEBUG_PRINTS void DbgPrintW(const char* fmt, ...); #else #define DbgPrintW(...)