c++ - 打印 : Wrong bottom margin

标签 c++ winapi printing mfc richedit

我正在打印一个编辑控件 - 首先将其内容复制到 Rich Edit 控件(至少 2.0 - 可以是 Rich Edit 3.0) - 然后从那里打印。

我已经一切正常......但边距很草率/不正确。

我已经反复检查了代码,验证了调试器中的数字,但打印页面上的边距(对于我可用于测试的打印机)仍然是错误的。

该代码或多或少是来自网络上可用的丰富编辑的各种打印示例的拷贝 - 包括 The Old New Thing、MSDN 文档和 CodeProject 等。

归结为(hdc 用于使用用户选择的纸张来源的用户选择的打印机):

// printer dot's per inch (pixels)
const CSize dpi = { GetDeviceCaps(hdc, LOGPIXELSX), GetDeviceCaps(hdc, LOGPIXELSY) };

// paper size (in printer's dots ~ pixels)
const CSize paper = { GetDeviceCaps(hdc, PHYSICALWIDTH), GetDeviceCaps(hdc, PHYSICALHEIGHT) };

// printable size (pixels) - this defines the largest possible usable rect for this printer
const CRect rcPrintable(CPoint(GetDeviceCaps(hdc, PHYSICALOFFSETX), GetDeviceCaps(hdc, PHYSICALOFFSETY)), CSize(GetDeviceCaps(hdc, HORZRES), GetDeviceCaps(hdc, VERTRES)));

// determine the paper extents using our desired margins without violating the device's minimum margins
const CSize margin = { dpi.cx / 4, dpi.cy / 2 };    // 1/4" horizontal x 1/2" vertical margins
const CRect rcPaper(__max(rcPrintable.left, margin.cx), __max(rcPrintable.top, margin.cy), __min(rcPrintable.right, paper.cx - margin.cx), __min(rcPrintable.bottom, paper.cy - margin.cy));

// convert paper size in printer dots (pixels) to paper size in TWIPS
const CRect rcPage(MulDiv(rcPaper.left, 1440, dpi.cx), MulDiv(rcPaper.top, 1440, dpi.cy), MulDiv(rcPaper.right, 1440, dpi.cx), MulDiv(rcPaper.bottom, 1440, dpi.cy));

// build our format range data
FORMATRANGE fr;
Zero(fr);
fr.hdc = hdc;
fr.hdcTarget = hdc;

// Set page rect to physical page size in TWIPS
fr.rc = rcPage;
fr.rcPage = rcPage;

// set our target device to  the printer
m_RichEdit.SetTargetDevice(hdc, rcPage.Width());

m_RichEdit.SetSel(0, -1);   // Select the entire contents.
m_RichEdit.GetSel(fr.chrg); // Get the selection into a CHARRANGE

// track the number of pages generated
unsigned nPages = 0;

// give this job a reasonable name
CString strPrintJobName = GetPrintJobName();

// Use GDI to print successive pages
DOCINFO di = { sizeof(di) };
di.lpszDocName = strPrintJobName;
if (!StartDoc(hdc, &di))
    throw CLabeledException(_T("Unable to start the print job"));

BOOL fSuccess = TRUE;
while (fr.chrg.cpMin < fr.chrg.cpMax)
{
    // start page
    fSuccess = StartPage(hdc) > 0;
    if (!fSuccess)
        break;

    // format page
    int cpMin = m_RichEdit.FormatRange(&fr, TRUE);

    // ensure we made forward progress (avoid infinite loop!)
    fSuccess = cpMin > fr.chrg.cpMin;
    if (!fSuccess)
        break;

    // render page
    fSuccess = m_RichEdit.DisplayBand(const_cast<CRect&>(rcPage));
    if (!fSuccess)
        break;

    // end page
    fSuccess = EndPage(hdc) > 0;
    if (!fSuccess)
        break;

    // update no. pages printed
    ++nPages;

    // update our new position
    fr.chrg.cpMin = cpMin;
}

// release internal cached data from rich edit control
m_RichEdit.FormatRange(nullptr, FALSE);

// complete or abort the print job
if (fSuccess)
{
    EndDoc(hdc);
    MessageBox(FormatString(_T("Printed %u pages"), nPages));
}
else
{
    DWORD dwError = GetLastError();
    AbortDoc(hdc);
    throw CContextException(FormatString(_T("Print failed on page %u"), nPages+1), dwError);
}

我的 600dpi 打印机的 rcPaper 输出为水平 5100 像素 x 垂直 6600 像素,由于该打印机的最小物理偏移/限制,所有尺寸均少于 100 点。

所以我的 1/4"x 1/2"页边距总是大于打印机的限制,我们最终得到的页面 = { 150, 300, 4950, 6300 }(像素)。

但实际打印时,我得到的上边距约为 5/8 英寸,下边距约为 3/16 英寸,左边距约为 3/8 英寸,右边距约为 1/8 英寸。

因此,就像打印机本身在发送给它的值(或丰富的编辑控件)之上添加了其限制(其 PHYSICALOFFSETXPHYSICALOFFSETY)正在用这些值抵消所有内容)。

...或者发生了其他事情和/或我误解了某些事情!

想法?

最佳答案

答案似乎是,上述数学在找到与打印机的功能和所需边距集的限制相匹配的“绝对”矩形时是正确的,但要创建输出矩形,需要减去物理偏移量为了使 0,0 在真实物理页面上为 0,0:

// subtract out the physical offsets
// note: I see no documentation that this is what must be done, yet, it must be done
//       otherwise the entire page is off by this exact amount :(
rcPaper.left -= rcPrintable.left;
rcPaper.right -= rcPrintable.left;
rcPaper.top -= rcPrintable.top;
rcPaper.bottom -= rcPrintable.top;

关于c++ - 打印 : Wrong bottom margin,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39705663/

相关文章:

macos - NSPrintOperation 附件 View 中的 NSScrollView 无法正确滚动

.net - 使用/clr :safe to enable unit testing? 编译 C++ 项目有什么缺点

c++ - 绑定(bind)与 Lambda?

c++ - 未找到符号 C++ 打印 vector 到控制台

java - 在读取 ArrayList 的同时打印 ArrayList 以获取打印条件

string - 调用fmt.Printf(“%+ v”,obj)时如何自定义结构的特定文件的文本

c++ - 为什么C++ STL不提供一套线程安全的容器?

c++ - "refclock.h"头文件构建错误,Windows 平台 SDK 的一部分

winapi - 是否可以在Reactor风格的操作中使用IOCP(或其他API)?

c++ - Windows GDI+ 应用程序中的奇怪显示错误