在启用GDI缩放的Windows 10上保存位图 [英] Saving Bitmaps on Windows 10 with GDI scaling active

查看:94
本文介绍了在启用GDI缩放的Windows 10上保存位图的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个带有工具栏的MFC应用程序(使用CMFCToolbar).我使用文件和资源中的位图动态创建工具栏位图. DIB具有不同的颜色格式.

I have a MFC application with toolbars (using CMFCToolbar). I create the toolbar bitmap on the fly using bitmaps from files and resources. The DIBs have different color formats.

  • 因此,我创建了一个与屏幕DC兼容的空位图工具栏图像.
  • 然后,我打开所有位图并将内容涂抹到工具栏位图上(GDI为我进行色彩空间转换和拉伸).
  • 然后将位图保存到24位DIB文件中.
  • 然后我创建工具栏对象并加载图像.

那已经使用了很长时间了,现在除了一种情况外,现在都在工作:

That has worked for ages and is working now except for one case:

最近,我们不得不为Windows 10 1703和更高版本启用GDI缩放. 在具有高分辨率显示屏和200%缩放比例的系统(例如Surface)上,会发生以下效果:

Recently we had to enable GDI scaling for Windows 10 1703 and later. On a system with high resolution display and 200% scaling (like Surface) the following effect occurs:

所有工具栏图标都失真.

All toolbar icons are distorted.

我也找到了原因:

保存合成的图像时,我只会得到图像的左上角四分之一. 与没有GDI缩放的普通分辨率显示相比,位图的宽度和高度没有变化(例如1024x15).但是该位图仅包含左上四分之一的像素(请参见下面的示例).

When saving the composed image I only get the top-left quarter of the image. Width and height of the bitmap did not change (say 1024x15) compared to normal resolution display without GDI scaling. But that bitmap only contains the pixels of the top-left quarter (see example below).

因此,我假设设备上下文告诉Windows大约200%的缩放比例.从源点向目标点拖动时,图像会自动按比例放大,但位图的尺寸不会改变.

So I assume the device context tells Windows about 200% scaling. When blitting from source to target the image gets scaled up automatically but the dimension of the bitmap does not change.

如何保存未缩放的位图?

How can I save the unscaled bitmap?

-或-

如何正确保存缩放的位图?从哪里得到丢失的像素?在哪里获得合适的尺寸? (HBITMAP仅指未缩放的尺寸.)

How can I correctly save the scaled bitmap? Where to get the missing pixels? Where to get proper dimensions? (HBITMAP refers only to unscaled dimensions).

示例:

没有GDI缩放,正确:

no GDI scaling, correct:

缩放比例为200%,尺寸相同,但只有正确图像的左上角四分之一:

200% scaling, same dimensions, but only top-left quarter of the correct image:

推荐答案

摘要和解决方案:

假设我们创建了与屏幕格式(DDB)兼容的内存位图:

Let's say we create a memory bitmap compatible to screen format (DDB):

CBitmap toolBitmap;
toolBitmap.CreateCompatibleBitmap (pDC, 1000, 20);

稍后,我们将某些内容添加到内存位图中(在这里无关紧要).现在,我们要保存位图(以DIB格式写入文件).

Later we blit something into the memory bitmap (does not matter here). Now we want to save the bitmap (write as DIB to file).

尽管我们知道尺寸(此处为1000x20),我们不应该使用它们.因为在Window 10和进程上激活了GDI缩放,并且使用了带有缩放的高分辨率显示-尺寸可能在内部发生了变化.因此,位图不再是1000x20.

Although we know the dimensions (here: 1000x20) we should not use them. Because on Window 10 and process has GDI scaling activated and high resolution display with scaling is used - the dimensions might have changed internally. Thus the bitmap is not 1000x20 anymore.

这失败了:

BITMAP bmHdr;
toolBitmap.GetObject(sizeof(BITMAP), &bmHdr);

位图标题包含原始尺寸(1000x20). 使用它们保存到文件会导致图像不完整.将仅存储左上部分.

The Bitmap header contains the original dimensions (1000x20). Using them for saving to file results in incomplete image. Only upper left part will be stored.

这是可行的-我们可以获取比例尺:

This one works - we can retrieve scaled dimensions:

BITMAPINFO bi = {};
bi.dwSize = sizeof(bi);
int result = GetDIBits(pDC->GetSafeHdc(), (HBITMAP)toolBitmap.GetSafeHandle(), 0, 0, NULL, &bi, DIB_RGB_COLORS);

现在,我们可以继续进行新的尝试.

Now we can proceed with new dimensions.

我最终使用了GDI +函​​数,该函数还保存了完整的(缩放的)位图:

I ended up using GDI+ functions, which also save the complete (scaled) bitmap:

Gdiplus::Bitmap bm((HBITMAP)toolBitmap.GetSafeHandle(), NULL);
Gdiplus::Status status = bm.Save(pwszFileName, &clsidEncoder, NULL);

我想有很多旧的MFC和GDI代码在Windows 10上激活的GDI缩放后将无法正常工作.

I presume there are tons of old MFC and GDI code which will not work correctly with activated GDI scaling on Windows 10.

这篇关于在启用GDI缩放的Windows 10上保存位图的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆