From 212bc1a61572a867ea6861e0c5d1ba1cea2fafac Mon Sep 17 00:00:00 2001 From: Takashi Sawanaka Date: Wed, 16 Sep 2020 23:56:13 +0900 Subject: [PATCH] Make the toolbar icon DPI-aware. fixes #370, fixes #276 --- Src/MainFrm.cpp | 128 +++++++++++++++++++++++++------ Src/Merge.cpp | 2 + Src/Merge.h | 1 + Src/Merge2.rc | 2 - Src/res/ToolbarEnabledMask.bmp | Bin 722 -> 0 bytes Src/res/ToolbarEnabledMask32.bmp | Bin 2790 -> 0 bytes Src/resource.h | 2 - 7 files changed, 108 insertions(+), 27 deletions(-) delete mode 100644 Src/res/ToolbarEnabledMask.bmp delete mode 100644 Src/res/ToolbarEnabledMask32.bmp diff --git a/Src/MainFrm.cpp b/Src/MainFrm.cpp index 959a7464835..ef7148e6c48 100644 --- a/Src/MainFrm.cpp +++ b/Src/MainFrm.cpp @@ -70,7 +70,7 @@ using boost::end; #define new DEBUG_NEW #endif -static void LoadToolbarImageList(int imageWidth, UINT nIDResource, UINT nIDResourceMask, bool bGrayscale, CImageList& ImgList); +static void LoadToolbarImageList(int orgImageWidth, int newImageHeight, UINT nIDResource, bool bGrayscale, CImageList& ImgList); static CPtrList &GetDocList(CMultiDocTemplate *pTemplate); template DocClass * GetMergeDocForDiff(CMultiDocTemplate *pTemplate, CDirDoc *pDirDoc, int nFiles, bool bMakeVisible = true); @@ -2024,22 +2024,22 @@ BOOL CMainFrame::CreateToolbar() /** @brief Load toolbar images from the resource. */ void CMainFrame::LoadToolbarImages() { - const int toolbarSize = 16 << GetOptionsMgr()->GetInt(OPT_TOOLBAR_SIZE); + const int toolbarNewImgSize = MulDiv(16, GetSystemMetrics(SM_CXSMICON), 16) << GetOptionsMgr()->GetInt(OPT_TOOLBAR_SIZE); + const int toolbarOrgImgSize = toolbarNewImgSize == 16 ? 16 : 32; CToolBarCtrl& BarCtrl = m_wndToolBar.GetToolBarCtrl(); m_ToolbarImages[TOOLBAR_IMAGES_ENABLED].DeleteImageList(); m_ToolbarImages[TOOLBAR_IMAGES_DISABLED].DeleteImageList(); CSize sizeButton(0, 0); - LoadToolbarImageList(toolbarSize, - toolbarSize <= 16 ? IDB_TOOLBAR_ENABLED : IDB_TOOLBAR_ENABLED32, - toolbarSize <= 16 ? IDB_TOOLBAR_ENABLED_MASK : IDB_TOOLBAR_ENABLED_MASK32, + LoadToolbarImageList(toolbarOrgImgSize, toolbarNewImgSize, + toolbarOrgImgSize <= 16 ? IDB_TOOLBAR_ENABLED : IDB_TOOLBAR_ENABLED32, false, m_ToolbarImages[TOOLBAR_IMAGES_ENABLED]); - LoadToolbarImageList(toolbarSize, - toolbarSize <= 16 ? IDB_TOOLBAR_ENABLED : IDB_TOOLBAR_ENABLED32, - toolbarSize <= 16 ? IDB_TOOLBAR_ENABLED_MASK : IDB_TOOLBAR_ENABLED_MASK32, + LoadToolbarImageList(toolbarOrgImgSize, toolbarNewImgSize, + toolbarOrgImgSize <= 16 ? IDB_TOOLBAR_ENABLED : IDB_TOOLBAR_ENABLED32, true, m_ToolbarImages[TOOLBAR_IMAGES_DISABLED]); - sizeButton = CSize(toolbarSize + 8, toolbarSize + 8); + + sizeButton = CSize(toolbarNewImgSize + 8, toolbarNewImgSize + 8); BarCtrl.SetButtonSize(sizeButton); BarCtrl.SetImageList(&m_ToolbarImages[TOOLBAR_IMAGES_ENABLED]); @@ -2056,29 +2056,111 @@ void CMainFrame::LoadToolbarImages() /** - * @brief Load a transparent 24-bit color image list. + * @brief Load a transparent 32-bit color image list. */ -static void LoadHiColImageList(UINT nIDResource, UINT nIDResourceMask, int nWidth, int nHeight, int nCount, bool bGrayscale, CImageList& ImgList) -{ - CBitmap bm, bmMask; - bm.Attach(LoadImage(AfxGetInstanceHandle(), MAKEINTRESOURCE(nIDResource), IMAGE_BITMAP, nWidth * nCount, nHeight, LR_DEFAULTCOLOR)); - bmMask.Attach(LoadImage(AfxGetInstanceHandle(), MAKEINTRESOURCE(nIDResourceMask), IMAGE_BITMAP, nWidth * nCount, nHeight, LR_MONOCHROME)); - if (bGrayscale) - GrayScale(&bm); - VERIFY(ImgList.Create(nWidth, nHeight, ILC_COLORDDB|ILC_MASK, nCount, 0)); - int nIndex = ImgList.Add(&bm, &bmMask); +static void LoadHiColImageList(UINT nIDResource, int nWidth, int nHeight, int nNewWidth, int nNewHeight, int nCount, bool bGrayscale, CImageList& ImgList) +{ + auto convert24bitImageTo32bit = [](int width, int height, bool grayscale, const BYTE* src, BYTE* dst) + { + for (int y = 0; y < height; ++y) + { + const BYTE* pSrc = src + y * ((width * 3 * 4 + 3) / 4); + BYTE* pDst = dst + (height - 1 - y) * ((width * 4 * 4 + 3) / 4); + if (!grayscale) + { + for (int x = 0; x < width; ++x) + { + if (pSrc[x * 3] == 0xff && pSrc[x * 3 + 1] == 0 && pSrc[x * 3 + 2] == 0xff) // rgb(0xff, 0, 0xff) == mask color + { + pDst[x * 4] = 0; + pDst[x * 4 + 1] = 0; + pDst[x * 4 + 2] = 0; + pDst[x * 4 + 3] = 0; + } + else + { + pDst[x * 4 + 0] = pSrc[x * 3 + 0]; + pDst[x * 4 + 1] = pSrc[x * 3 + 1]; + pDst[x * 4 + 2] = pSrc[x * 3 + 2]; + pDst[x * 4 + 3] = 0xff; + } + } + } + else + { + for (int x = 0; x < width; ++x) + { + if (pSrc[x * 3] == 0xff && pSrc[x * 3 + 1] == 0 && pSrc[x * 3 + 2] == 0xff) // rgb(0xff, 0, 0xff) == mask color + { + pDst[x * 4] = 0; + pDst[x * 4 + 1] = 0; + pDst[x * 4 + 2] = 0; + pDst[x * 4 + 3] = 0; + } + else + { + const BYTE b = pSrc[x * 3]; + const BYTE g = pSrc[x * 3 + 1]; + const BYTE r = pSrc[x * 3 + 2]; + const BYTE gray = static_cast( + (static_cast(0.114 * 256) * (((255 - b) >> 1) + b) + + static_cast(0.587 * 256) * (((255 - g) >> 1) + g) + + static_cast(0.299 * 256) * (((255 - r) >> 1) + r)) >> 8); + pDst[x * 4 + 0] = gray; + pDst[x * 4 + 1] = gray; + pDst[x * 4 + 2] = gray; + pDst[x * 4 + 3] = 0xff; + } + } + } + } + }; + + auto createImageListFromBitmap = [](CImageList& imgList, Gdiplus::Bitmap& bitmap, int width, int height, int count) + { + CBitmap bm; + HBITMAP hBitmap; + bitmap.GetHBITMAP(Gdiplus::Color::Transparent, &hBitmap); + bm.Attach(hBitmap); + + VERIFY(imgList.Create(width, height, ILC_COLOR32, count, 0)); + int nIndex = imgList.Add(&bm, nullptr); ASSERT(-1 != nIndex); + }; + + ATL::CImage img; + img.Attach((HBITMAP)LoadImage(AfxGetInstanceHandle(), MAKEINTRESOURCE(nIDResource), IMAGE_BITMAP, nWidth * nCount, nHeight, LR_CREATEDIBSECTION), ATL::CImage::DIBOR_TOPDOWN); + const int stride = (nWidth * nCount * 4 * 4 + 3) / 4; + std::vector buf(stride * nHeight); + convert24bitImageTo32bit(nWidth * nCount, nHeight, bGrayscale, reinterpret_cast(img.GetBits()), buf.data()); + + if (nWidth != nNewWidth && nHeight != nNewHeight) + { + Gdiplus::Bitmap bitmapSrc(nWidth * nCount, nHeight, stride, PixelFormat32bppPARGB, buf.data()); + Gdiplus::Bitmap bitmapDst(nNewWidth * nCount, nNewHeight, PixelFormat32bppPARGB); + Gdiplus::Graphics dcDst(&bitmapDst); + dcDst.SetInterpolationMode(Gdiplus::InterpolationMode::InterpolationModeHighQualityBicubic); + dcDst.DrawImage(&bitmapSrc, 0, 0, nNewWidth * nCount, nNewHeight); + + createImageListFromBitmap(ImgList, bitmapDst, nNewWidth, nNewHeight, nCount); + } + else + { + Gdiplus::Bitmap bitmapDst(nWidth * nCount, nHeight, stride, PixelFormat32bppPARGB, buf.data()); + + createImageListFromBitmap(ImgList, bitmapDst, nNewWidth, nNewHeight, nCount); + } } /** * @brief Load toolbar image list. */ -static void LoadToolbarImageList(int imageWidth, UINT nIDResource, UINT nIDResourceMask, bool bGrayscale, - CImageList& ImgList) +static void LoadToolbarImageList(int orgImageWidth, int newImageWidth, UINT nIDResource, bool bGrayscale, CImageList& ImgList) { const int ImageCount = 22; - const int imageHeight = imageWidth - 1; - LoadHiColImageList(nIDResource, nIDResourceMask, imageWidth, imageHeight, ImageCount, bGrayscale, ImgList); + const int orgImageHeight = orgImageWidth - 1; + const int newImageHeight = newImageWidth - 1; + LoadHiColImageList(nIDResource, orgImageWidth, orgImageHeight, newImageWidth, newImageHeight, ImageCount, bGrayscale, ImgList); } /** diff --git a/Src/Merge.cpp b/Src/Merge.cpp index c5130614ecd..c960e84fc6d 100644 --- a/Src/Merge.cpp +++ b/Src/Merge.cpp @@ -150,6 +150,8 @@ BOOL CMergeApp::InitInstance() InitCommonControls(); // initialize common control library CWinApp::InitInstance(); // call parent class method + m_imageForInitializingGdiplus.Load((IStream*)nullptr); // initialize GDI+ + // Runtime switch so programmer may set this in interactive debugger int dbgmem = 0; if (dbgmem) diff --git a/Src/Merge.h b/Src/Merge.h index b5d27c6e946..adf7dcd841a 100644 --- a/Src/Merge.h +++ b/Src/Merge.h @@ -169,6 +169,7 @@ class CMergeApp : public CWinApp LONG m_nActiveOperations; /**< Active operations count. */ bool m_bMergingMode; /**< Merging or Edit mode */ CFont m_fontGUI; + ATL::CImage m_imageForInitializingGdiplus; }; extern CMergeApp theApp; diff --git a/Src/Merge2.rc b/Src/Merge2.rc index 6469eb8a7fb..01a3e6e41db 100644 --- a/Src/Merge2.rc +++ b/Src/Merge2.rc @@ -113,8 +113,6 @@ IDR_MARGIN_ICONS_PNG IMAGE "res\\mg_icons.png" IDB_TOOLBAR_ENABLED8BIT BITMAP "res\\ToolbarEnabled8bit.bmp" IDB_TOOLBAR_ENABLED BITMAP "res\\ToolbarEnabled.bmp" IDB_TOOLBAR_ENABLED32 BITMAP "res\\ToolbarEnabled32.bmp" -IDB_TOOLBAR_ENABLED_MASK BITMAP "res\\ToolbarEnabledMask.bmp" -IDB_TOOLBAR_ENABLED_MASK32 BITMAP "res\\ToolbarEnabledMask32.bmp" IDB_EDIT_COPY BITMAP "res\\copy.bmp" IDB_EDIT_CUT BITMAP "res\\cut.bmp" IDB_EDIT_PASTE BITMAP "res\\paste.bmp" diff --git a/Src/res/ToolbarEnabledMask.bmp b/Src/res/ToolbarEnabledMask.bmp deleted file mode 100644 index 14f353cd6010f6536b05f2df70816c696ccec823..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 722 zcmZ9KzfQw25XR39k~35UwoZg@jFs3aV&@%r1va)Cu`t2H1G&n;f>enou+*VzP?kuo ze0+DdrNUYMlk?A)&v(AN|DKTA4aO_<2Se0gHfUlW*zZnLS4SS0nV5sY42u;}k7Iq~ zjK^A?yB)hqSIkS-dh$xg{ap2wv#j-26P!}7Bf*H^(3{V>0OK0j~4 z-cG=NwGJ}TAKz40VuRJ0x#=JrEUcct+RTovvgyki`RrG*Srfe^mdsg|cCqP*Fv!A) zFCUf&8kfvW{mvL%Uex+Zx@19AWXtR{vxLjUeXymGIErQVWP^~J6j@?Q>};8J zi(@va9b3^V{(tNYKIm9fewy|ZBR4E4<+#31?2`=_r4qvQ4RS0wW6n9N=iwYI@)p~1 zb<73}?NSS7sfE^Uympmi)EE}`scI6}8%?Jy7JogMfW DUN+W_ diff --git a/Src/res/ToolbarEnabledMask32.bmp b/Src/res/ToolbarEnabledMask32.bmp deleted file mode 100644 index d12f9cd7c1ef5aed4be90b4a3e9ec2f1d6e6bdae..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2790 zcmb`JJB}1F5QfVb(GslG5(l7DPC<{zxx*kXfJBPaCV_B{K*}xfieSUNf>%gvNRLPc zY3Snr%k9~IunPe_Q&WDFzb=eiSJ5S*gzW>ThYoFC!KqhQKUF{4_z5?`h7ttt`9kiM_IjufwSGXGn{mTy zc0@2)AZ6Fn#QT>GxC`by2GfRG2-WPfD~E@E@Ty}rf>)M1n7Uo>LXP^=!w zeW!h!eDcGJJII!6!S>?sSB8#bDJWQ(`Y6&;tUY$Ha@sf1MR#0rkFu@OoV(xM!W~39 zO6Inz1GsfSTn{VmLDGyHq}}h1SOZ!6t8kyfK8=m)5!{Mg{Mx#4%*Nu|SE))9e}i=U z-EiVM&OdNHp*3JxAy$vI>H%EObxRAbxV}lV_+ofpYv#fk23k)#dMqe}?Ge(03t#&x zX0GHpLb=5Cochak9Q=ImqGGAwfw?<&3Tq{&GL`u z1M?WE$fSln&L75ngOSKLf2`8P-(BYJ13EG3d}oe2vMs_vlO~@#cokm?`y1{C=MK)J zG~s>>yldP~*q!ol)j9PQq;-MChAv?}HoaG~s?uyc4Qlg)!Au#$IFoDenuO z>kYZ zVa&lM-^cH8ACtSjH{oZOz~w<}ESllr`A~R8lYKz0QS$$XbNqj>XN>O#jA-{zsJI5O z(|GnTT;`hP-vxPB_`hS%2aXNc*%bS~qnx)i*eg$_T=>)!KZ{1cB;*7|FUk9Xk3E+W rZF4SN#X8`RT3~#~Cv(R;GGxtuj;9p6q7&v3d~_6vXRH2V_doP+MI