场景

1.使用win32绘图时, 最简单的api是使用 graphics.DrawImage(image,x,y)来绘制, 可是这个api有个坑,它的图片显示完整和设备分辨率(显卡)有关.

说明

1.Windows使用以下约定: 1逻辑英寸(logical inch)== 96像素(pixels) == 72 points.

2.我们创建的程序一般是DPI-Aware 程序, 因为这种程序可以避免DWM自动执行DPI缩放, 它该是多少像素就是多少像素, 不会随着设备DPI的变化而变化, 同时DPI-Aware的程序改进了在更高DPI设备上的呈现; 一般在项目文件x.exe.embed.manifest里会看到类似的声明.

Dots per inch (DPI)
Device-independent pixel (DIPs).
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3" >
  <asmv3:application>
    <asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
      <dpiAware>true</dpiAware>
    </asmv3:windowsSettings>
  </asmv3:application>
</assembly>

3.GDI是通过pixel来绘制指定大小的, 它意味着如果你让GDI绘制200x100的矩形, 那么它就会在屏幕上绘制200x100像素的矩形. 不管DPI如何设置. 然而, GDI 字体大小是随着当前DPI设置而缩放的. 换句话来说就是, 如果你创建了一个72-point的字体, 字体的大小将会在96 DPI里是96像素, 在144 DPI里是144 pixels.

DPI setting   DIP size
96            1 pixel
120           1.25 pixels
144           1.5 pixels

4.现在说下graphics.DrawImage的绘图被缩放显示不正常的原因, 当用户设备DPI的值高于96 dpi 时,假设是120 dpi. 这样一张200x100 96dpi的图片实际的大小是 250x125, 而graphics.DrawImage(image,x,y)这个函数并没有指定绘制目标和源矩形, 所以默认是源矩形的200x100,目标矩形的200x100, 而源矩形实际上是250x150了,所以只绘制了图片的一部分. 这部分内容也是推理出来的, 微软官方的DPI and Device-Independent Pixels并没有说明图片在高DPI时是否会缩放, 只说明了字体会缩放.

在96DPI显示正常的图片:

在高DPI显示不正常的图片:

5.获取设备DPI的方法:


void InitializeDPIScale(HWND hwnd)
{
    HDC hdc = GetDC(hwnd);
    g_DPIScaleX = GetDeviceCaps(hdc, LOGPIXELSX) / 96.0f;
    g_DPIScaleY = GetDeviceCaps(hdc, LOGPIXELSY) / 96.0f;
    ReleaseDC(hwnd, hdc);
}

解决

1.使用带Rect方式的绘制,graphics.DrawImage(image,Rect)等其他重载函数, 让图片自动缩放.

class Utils
{
public:
    static void DrawImage(Gdiplus::Graphics& graphics,Gdiplus::Image* image,
        int x,int y)
    {
        Gdiplus::Rect dest_rect(x,y,image->GetWidth(),image->GetHeight());
        graphics.DrawImage(image,dest_rect,0,0,image->GetWidth(),image->GetHeight(),
            Gdiplus::UnitPixel);
    }
};

参考

DPI and Device-Independent Pixels

Graphics.DrawImage logo scaling incorrectly on a large image

Graphics.DrawImage 图像质量变差

[ATL/WTL]_[初级]_[关于graphics.DrawImage绘图时显示不正常的问题]的更多相关文章

  1. [ATL/WTL]_[初级]_[选择目录对话框]

    场景 1.起因是创建标准选择目录对话框时使用了 SHCreateItemFromParsingName 函数, 这个函数支持vista以上系统. 之后再winxp上运行就报错: 无法定位程序输入点 S ...

  2. [C/C++标准库]_[初级]_[转换UTC时间到local本地时间]

    场景 1.如果有面向全球用户的网站, 一般在存储时间数据时存储的是UTC格式的时间, 这样时间是统一的, 并可以根据当地时区来进行准确的转换. 2.存储本地时间的问题就在于如果换了时区, 那么显示的时 ...

  3. [Zlib]_[初级]_[使用zlib库压缩和解压STL string]

    场景 1.一般在使用文本json传输数据, 数据量特别大时,传输的过程就特别耗时, 因为带宽或者socket的缓存是有限制的, 数据量越大, 传输时间就越长. 网站一般使用gzip来压缩成二进制. 说 ...

  4. [C/C++11]_[初级]_[std::bind介绍和使用]

    场景 1.C++11 引入了std::function 对象, 这个对象可以通过std::bind封装所有的函数, 并通过代理调用这个std::function的方式调用这个函数. 比如通过统一的方式 ...

  5. [数据库]_[初级]_[sqlite3简单使用]

    场景 1.sqlite3在很多小型项目都会用到, 比如用来存储Android的联系人,短信等. 这个小巧的sqlite3是文件型的数据库, 也方便做配置文件和程序打包. 使用sql查询也方面. 所以s ...

  6. [ATL/WTL]_[中级]_[保存CBitmap到文件-保存屏幕内容到文件]

    场景: 1. 在做图片处理时,比方放大后或加特效后须要保存CBitmap(HBITMAP)到文件. 2.截取屏幕内容到文件时. 3.不须要增加第3方库时. 说明: 这段代码部分来自网上.第一次学atl ...

  7. Oracle学习总结_day03_day04_条件查询_排序_函数_子查询

    本文为博主辛苦总结,希望自己以后返回来看的时候理解更深刻,也希望可以起到帮助初学者的作用. 转载请注明 出自 : luogg的博客园 谢谢配合! day03_条件查询_排序_函数 清空回收站: PUR ...

  8. C Primer Plus_第6章_循环_编程练习

    1.题略 #include int main(void) { int i; char ch[26]; for (i = 97; i <= (97+25); i++) { ch[i-97] = i ...

  9. 转:HIBERNATE一些_方法_@注解_代码示例---写的非常好

    HIBERNATE一些_方法_@注解_代码示例操作数据库7步骤 : 1 创建一个SessionFactory对象 2 创建Session对象 3 开启事务Transaction : hibernate ...

随机推荐

  1. 第一章:了解SQL_数据库基础

    什么是数据库(database): 数据库(database)是保存有组织的数据的容器(通常是一个文件或一组文件).数据库是一种以某种有组织的方式存储的数据集合.   表(table): 表(tabl ...

  2. iOS设计模式 - 中介者

    iOS设计模式 - 中介者 原理图 说明 用一个中介对象来封装一系列的对象交互.中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互. 注:中介者对象本身没有复用价值 ...

  3. 使用SDWebImage淡入淡出的方式加载图片

    使用SDWebImage淡入淡出的方式加载图片 效果: 请通过以下方式下载源码: 找到它修改文件的地方: 以下是使用源码: // // ViewController.m // SDWebImageFa ...

  4. Python学习---Django关于POST的请求解析源码分析

    当有请求到来之后,先判断请求头content_type是不是[application/x-www-form-urlencoded] --> 如果是则将请求数据赋值给request.body然后解 ...

  5. IIS6与IIS7中的w3wp工作进程

    在IIS6中,每一个网站都有对应的应用程序池,在应用程序池有运行着网站的Application,在默认情况下,所有的网站的应用程序都会分配到默认的应用程序池当中,   当然,我们可以新建一个应用程序池 ...

  6. Hadoop HBase概念学习系列之HBase里的Client(二十二)

    这个,很简单,但凡是略懂大数据的,就很清楚,不多说,直接上图.

  7. Hadoop HBase概念学习系列之HBase里的长表VS宽表VS窄表(十五)

    有时候啊,HBase表的设计方案通常,还会考虑如下一些因素,当然,这只是考虑范围里的部分呢. 更多的行还是更多的版本?后者使用了HBase自带的功能.但是需要在列簇中定义最大版本数,这样做可能有风险. ...

  8. September 28th 2017 Week 39th Thursday

    Every saint has a past and every sinner has a future. 圣人皆有过去,罪人皆有未来. If you were a sinner in the pas ...

  9. 【Alpha】事后诸葛亮

    一. 项目的预期计划 / 项目的现实进展 详见Alpha冲刺博客第一篇 二. 完成项目过程中的体会 详见Alpha冲刺博客第十二篇 三. 团队成员的分工及在Alpha阶段的工作量比例 成员 职务 博客 ...

  10. [CEOI2017]Building Bridges

    题目 斜率优化思博题,不想写了 之后就一直\(95\)了,于是靠肮脏的打表 就是更新了一下凸壳上二分斜率的写法,非常清爽好写 就当是挂个板子了 #include<algorithm> #i ...