SOUI里实现打印预览续
之前写了一篇关于SOUI里实现打印预览的短文,为什么现在又有续呢,原因是之前实现的打印预览出现了水土不服,反复测试在我的环境没问题的实现在有高清分辨率显示器的环境下,出现打印预览显示不全的问题。为了说明问题,先来一段我实现打印的模板配置文件
<PrintTemplate name="A4_CUSTOMER_FOCUS" description="A4突出客户信息" paperWidth="2020" paperHeight="2890"><!-- 顶部品牌区 --><Item type="text" x="0" y="10" width="2020" height="-1" align="center" font="size:55,bold:1"><Content>{CompanyName}</Content></Item><Item type="text" x="0" y="90" width="2020" height="-1" align="center" font="size:30"><Content>{CompanyAddress} | {CompanyPhone}</Content></Item>
这里只有一小部分,其它部分基本一致,为了方便我的配置实现使用的mm单位,这样,很方便就可以通过配置来定义模板,因为使用MM就很直观。这样我就需要在代码里使用
// 0.1mm一个单位
dc.SetMapMode(MM_LOMETRIC);来实现,水土不服也就出现在这个代码上,因为我为了画出预览图,那么就需要知道确切的DPI这样才能计算出需要的内存DC大小,这里就分了两种情况,一是使用清单让系统知道我的程序支持DPI识别处理,还有就是不处理DPI,正常情况下的内存DC计算方式为
SIZE sz = { dmPaperWidth * g_curPrintDpi.XDPI / 254, dmPaperHeight * g_curPrintDpi.YDPI / 254 };
其中DPI可以通过GetDeviceCaps(hdc,LOGPIXELSX)和GetDeviceCaps(hdc,LOGPIXELSY)来获取,对于不支持DPI识别的程序,那么它始终返回96,对于支持DPI的返回96*系统设置的缩放。水土不服的来源正源自此处,不管使用哪种方式获取,最后都是有问题的,先说不支持DPI识别的情况,如果放在高分率的显示上,很显然,同样宽度会有更多的点,这样计算出的内存DC大小就会小,不足以容纳内容。再说支持DPI识别的情况,如果是正常的使用系统推荐的缩放那么一般也可以得到比较准的计算,但是上面说的,在使用DPI识别的情况,API并没有正确返回屏的真实DPI,而MM_LOMETRIC的映射方式是基于真实DPI的,也就是如果系统推荐的是100%绽放,那系统设置了125%的缩放,最后计算的大小则会比需要的大,而且这个缩放完全是人为不可控的。总不能告诉别人,你用我的软件必须严格按系统推荐缩放使用吧(虽然系统推荐通常就是最佳的选择)。针对这个问题,我觉得大概有如下可行方式
方式一、获取系统推荐绽放然后和96计算得到它的最接近DPI,然后使用这个DPI来计算DC大小。(这个绘制代码基本不需要任何修改,但是我使用过搜索的AI都没有得到比较好的方法。按理说这个推荐应该在注册表里能找到,还没时间研究,有知道的佬告诉一下)
方式二、使用自定义映射,即使用SetWindowExtEx和SetViewportExtEx来实现,目前我使用这个方式来实现,其中nScale 是缩放系数,这样不仅可以不需要管系统DPI,并且可以自由实现缩放。
SetMapMode(MM_ANISOTROPIC);
SetWindowExtEx(hDC, 254, 254, NULL);
SetViewportExtEx(hDC, 96 * nScale / 100, 96 * nScale / 100, NULL);
这个方式需要注意它的坐标系Y的方向和MM_LOMETRIC是相反,尝试使用SetViewportExtEx(hDC, 96 * nScale / 100, -96 * nScale / 100, NULL);来 实现没有成功。文字输出完全不对。当然这个方式也不是完全没有问题正常输出 使用SetWindowExtEx后输出
可以看到中文和字母的间格是不对的,此外还有数字间距不知道如何解决目前。
目前先到这,有更好的解决方法再水一章