#include "stdafx.h" #include "EasyPrinterV1.h" #include CEasyPrinterV1::CEasyPrinterV1() { } CEasyPrinterV1::~CEasyPrinterV1() { } /************************************************************************/ /* 函数:[3/7/2017 Jeff]; /* 描述:; /* 参数:; /* [IN] strText:输入的文本内容(必须是ASCII或多字节); /* [IN] nRectWide:文本显示的区域宽度; /* [OUT] vtSubText:返回换行的字符串数组; /* 返回:void; /* 注意:任何字节打印的长度都是固定的,任何汉字的长度是2倍于字节打印长度; /* 示例:; /* /* 修改:; /* 日期:; /* 内容:; /************************************************************************/ void CEasyPrinterV1::TextDownwards(IN TString strText, IN const INT& nRectWide, OUT vector& vtSubText) { if (nRectWide < 1) { TRACE("图元宽 - 2*边距值 < 0 \n"); return; } TString str; SIZE fontSize; // 计算出一个字节的宽度(注:是一个byte的长度); GetTextExtentPoint32(m_dcPrinter, "1", 1, &fontSize); const INT nCharWide = fontSize.cx; // 字符数; INT nCharSum = 0; // 区域宽度/字符宽度 = 大约字符数 此值固定; const INT nCharCount = nRectWide / nCharWide; // 按 "\r\n" 分段; INT nIndex = 0; strText.append("\r\n"); vector vtWrapText; do { if ((nIndex = strText.find("\r\n")) != TString::npos) { str = strText.substr(0, nIndex); if (str.size() == 0) vtWrapText.push_back("\r\n"); else vtWrapText.push_back(str); strText = strText.substr(nIndex + strlen("\r\n")); } } while (strText.find("\r\n") != TString::npos); for (vector::iterator it = vtWrapText.begin(); it != vtWrapText.end(); it++) { strText = it->c_str(); do { // 计算出大约字符数,也是分行的大约位置; nCharSum = nCharCount; if (strText.length() > nCharSum) { str = strText.substr(0, nCharSum); GetTextExtentPoint32(m_dcPrinter, str.c_str(), str.length(), &fontSize); if (nRectWide >= fontSize.cx) { do { if (nCharSum >= strText.size()) break; // 仍短,加长度; str = strText.substr(0, ++nCharSum); // 是否有半个汉字; if (IsHalfChineseWord(str.c_str())) { str = strText.substr(0, ++nCharSum); } // 再获取字符串宽度; GetTextExtentPoint32(m_dcPrinter, str.c_str(), str.length(), &fontSize); } while (fontSize.cx < nRectWide); str = strText.substr(0, --nCharSum); if (IsHalfChineseWord(str.c_str())) { --nCharSum; str = strText.substr(0, nCharSum); } strText = strText.substr(nCharSum); vtSubText.push_back(str); } else/* if ( fontSize.cx > rcOld.Width() )*/ { do { if (nCharSum <= 0) break; // 仍长,减长度; str = strText.substr(0, --nCharSum); // 是否有半个汉字; if (IsHalfChineseWord(str.c_str())) { str = strText.substr(0, --nCharSum); } // 再获取字符串宽度; GetTextExtentPoint32(m_dcPrinter, str.c_str(), str.length(), &fontSize); } while (fontSize.cx > nRectWide); str = strText.substr(0, ++nCharSum); if (IsHalfChineseWord(str.c_str())) { ++nCharSum; str = strText.substr(0, nCharSum); } strText = strText.substr(nCharSum); vtSubText.push_back(str); } GetTextExtentPoint32(m_dcPrinter, strText.c_str(), strText.length(), &fontSize); if (fontSize.cx <= nRectWide) vtSubText.push_back(strText); } else { // 长度不溢出; vtSubText.push_back(strText); GetTextExtentPoint32(m_dcPrinter, strText.c_str(), strText.length(), &fontSize); } } while (fontSize.cx > nRectWide); } } /************************************************************************/ /* 函数:[3/10/2017 Jeff]; /* 描述:; /* 参数:; /* [IN] :; /* [OUT] :; /* [IN/OUT] :; /* 返回:0 = 未画,1 = 画一半,2 = 全画完; /* 注意:; /* 示例:; /* /* 修改:; /* 日期:; /* 内容:; /************************************************************************/ INT CEasyPrinterV1::DrawRectange(IN CRect rc, IN INT nLineWide, IN INT leftLineType, IN INT topLineType, IN INT rightLineType, IN INT bottomLineType) { INT nDrawResult = 0; if (rc.top >= m_printlist.rcPage.bottom) { // 未画,表示需要换页; return nDrawResult; } // 判断区域是否超过底部; if (rc.bottom > m_printlist.rcPage.bottom) { // 画一半,剩余要换页; nDrawResult = 1; rc.bottom = m_printlist.rcPage.bottom; // 如果只画了一半,下边透明; //topLineType = bottomLineType = 0; } else { // 全画; nDrawResult = 2; } CPen pen[4]; // 画左边线; if (leftLineType == 0) pen[0].CreatePen(PS_NULL, nLineWide, RGB(0, 0, 0)); else if (leftLineType == 1) pen[0].CreatePen(PS_DASH, nLineWide, RGB(0, 0, 0)); else if (leftLineType == 2) pen[0].CreatePen(PS_SOLID, nLineWide, RGB(0, 0, 0)); // 选入DC中; m_dcPrinter.SelectObject(&pen[0]); m_dcPrinter.MoveTo(rc.left, rc.top); m_dcPrinter.LineTo(rc.left, rc.bottom); pen[0].DeleteObject(); // 画上边线; if (topLineType == 0) pen[1].CreatePen(PS_NULL, nLineWide, RGB(0, 0, 0)); else if (topLineType == 1) pen[1].CreatePen(PS_DASH, nLineWide, RGB(0, 0, 0)); else if (topLineType == 2) pen[1].CreatePen(PS_SOLID, nLineWide, RGB(0, 0, 0)); // 选入DC中; m_dcPrinter.SelectObject(&pen[1]); m_dcPrinter.MoveTo(rc.left, rc.top); m_dcPrinter.LineTo(rc.right, rc.top); pen[1].DeleteObject(); // 画右边线; if (rightLineType == 0) pen[2].CreatePen(PS_NULL, nLineWide, RGB(0, 0, 0)); else if (rightLineType == 1) pen[2].CreatePen(PS_DASH, nLineWide, RGB(0, 0, 0)); else if (rightLineType == 2) pen[2].CreatePen(PS_SOLID, nLineWide, RGB(0, 0, 0)); // 选入DC中; m_dcPrinter.SelectObject(&pen[2]); m_dcPrinter.MoveTo(rc.right, rc.top); m_dcPrinter.LineTo(rc.right, rc.bottom); pen[2].DeleteObject(); // 画下边线; if (bottomLineType == 0) pen[3].CreatePen(PS_NULL, nLineWide, RGB(0, 0, 0)); else if (bottomLineType == 1) pen[3].CreatePen(PS_DASH, nLineWide, RGB(0, 0, 0)); else if (bottomLineType == 2) pen[3].CreatePen(PS_SOLID, nLineWide, RGB(0, 0, 0)); // 选入DC中; m_dcPrinter.SelectObject(&pen[3]); m_dcPrinter.MoveTo(rc.left, rc.bottom); m_dcPrinter.LineTo(rc.right, rc.bottom); pen[3].DeleteObject(); return nDrawResult; } /************************************************************************/ /* 函数:[3/9/2017 Jeff]; /* 描述:; /* 参数:; /* [IN] nTextWide:文本字体长度; /* [OUT] :; /* [IN/OUT] :; /* 返回:void; /* 注意:; /* 示例:; /* /* 修改:; /* 日期:; /* 内容:; /************************************************************************/ void CEasyPrinterV1::DrawText(IN TString strText, IN CRect rcText, IN INT nTextWide, IN INT nAlignType /* = 0 */) { switch (nAlignType) { case 0: // 左对齐,默认; break; case 1: // 水平居中; rcText.left += (rcText.Width() - nTextWide) / 2; break; case 2: // 右对齐; rcText.left += rcText.Width() - nTextWide; break; case 3: // 垂直居中; break; default: break; } m_dcPrinter.TextOut(rcText.left, rcText.top, strText.c_str()); } /************************************************************************/ /* 函数:[3/16/2017 Jeff]; /* 描述:; /* 参数:; /* [IN] :; /* [OUT] :; /* [IN/OUT] :; /* 返回:void; /* 注意:; /* 示例:; /* /* 修改:; /* 日期:; /* 内容:; /************************************************************************/ void CEasyPrinterV1::CalcPrinterCell(IN STPrintCell &PrintCell) { // 默认设置所有区域与原始区域一致; PrintCell.rcChg = PrintCell.rcOrg; // 填充模式; if (PrintCell.nFillerType == 0) {// 文本填充; SIZE fontSize; INT nTextlen = PrintCell.strTextContent.size(); // 根据文本特性,计算出文本长度和高度; SetTextFont(PrintCell.nTextFontSize, PrintCell.bTextBold, PrintCell.bTextItalic, PrintCell.strTextFontName); INT nRet = GetTextExtentPoint32(m_dcPrinter, PrintCell.strTextContent.c_str(), nTextlen, &fontSize); // 在打印机设备DC上获取文本长度; if (fontSize.cx > PrintCell.rcOrg.Width()) {// 字体内容溢出; TextDownwards(PrintCell.strTextContent, PrintCell.rcOrg.Width() - PrintCell.nCellMargins * 2, PrintCell.vtSubText); // 是否向下延伸; if (PrintCell.bAutoWraps && PrintCell.vtSubText.size()) { // 如果是bDownwards属性,清空; PrintCell.strTextContent.clear(); if (!PrintCell.rcOrg.IsRectEmpty() && !PrintCell.rcOrg.IsRectNull()) {// 表格区域不能无效; // 新高 = 字体高*行数 + 上下边距*2 + (行 - 1)*行间距; PrintCell.rcChg.bottom = PrintCell.rcChg.top + PrintCell.vtSubText.size()*fontSize.cy + PrintCell.nCellMargins * 2 + PrintCell.nLineSpacing*(PrintCell.vtSubText.size() - 1); } } } } else if (PrintCell.nFillerType == 1) {// 图片填充,需要将图片压缩到指定大小; TRACE("图片显示区域大小不需要改变\n"); } // 是否已经向下延伸了; if (PrintCell.rcOrg != PrintCell.rcChg) PrintCell.bHasWrapped = TRUE; else PrintCell.bHasWrapped = FALSE; } /************************************************************************/ /* 函数:[3/16/2017 Jeff]; /* 描述:; /* 参数:; /* [IN] :; /* [OUT] :; /* [IN/OUT] :; /* 返回:void; /* 注意:; /* 示例:; /* /* 修改:; /* 日期:; /* 内容:; /************************************************************************/ void CEasyPrinterV1::CellTBTypesetting() { // 首先处理的是上下相邻的两个图元,将相衔接一起; vector::iterator it = m_printlist.vtPrintCell.begin(); for (; it != m_printlist.vtPrintCell.end(); it++) { vector::iterator it1 = m_printlist.vtPrintCell.begin(); for (; it1 != m_printlist.vtPrintCell.end(); it1++) { if (it != it1) { if (it->rcOrg.bottom == it1->rcOrg.top) { // 判断是否已经衔接; if (it->rcChg.bottom != it1->rcChg.top) { if (it1->bTypesetting) { if (it->rcChg.bottom > it1->rcChg.top) { it1->rcChg.OffsetRect(0, it->rcChg.bottom - it1->rcChg.top); } } else { if (it->rcChg.bottom > it1->rcChg.top) { it1->rcChg.OffsetRect(0, it->rcChg.bottom - it1->rcChg.top); } } } } } } } } void CEasyPrinterV1::CellBBTypesetting() { // 其次,再处理同底的图元,不使用offset; vector::iterator it = m_printlist.vtPrintCell.begin(); for (; it != m_printlist.vtPrintCell.end(); it++) { vector::iterator it1 = m_printlist.vtPrintCell.begin(); for (; it1 != m_printlist.vtPrintCell.end(); it1++) { if (it != it1) { if (it->rcOrg.bottom == it1->rcOrg.bottom) { if (it->rcChg.bottom != it1->rcChg.bottom) { if (it->rcChg.bottom > it1->rcChg.bottom) { it1->rcChg.bottom = it->rcChg.bottom; } else { it->rcChg.bottom = it1->rcChg.bottom; } // 变更了上下衔接; CellTBTypesetting(); } } } } } } BOOL CEasyPrinterV1::PrintByJson() { // 1.初始打印机; if (FALSE == InitialzePrinter(m_printlist.strPrinterName.c_str())) return FALSE; // 3.计算每个图元在使用填充后的实际大小; vector::iterator it = m_printlist.vtPrintCell.begin(); for (; it != m_printlist.vtPrintCell.end(); it++) {// 不建议图元同时具有向下和向右延伸的特性; CalcPrinterCell(*it); } CellTBTypesetting(); CellBBTypesetting(); #if 1// 让字体适应固定的图元区域; ////////////////////////////////////////////////////////////////////////// // 如果固定大小的单元格变化了,根据变化后的区域重新计算文本字体大小; it = m_printlist.vtPrintCell.begin(); for (; it != m_printlist.vtPrintCell.end(); it++) { if (!it->bAutoWraps) { SIZE fontSize; INT nTextlen = it->strTextContent.size(); // 根据文本特性,计算出文本长度和高度; SetTextFont(it->nTextFontSize, it->bTextBold, it->bTextItalic, it->strTextFontName); GetTextExtentPoint32(m_dcPrinter, "1", 1, &fontSize); // 在打印机设备DC上获取文本长度; // 新高 = 字体高*行数 + 上下边距*2 + (行 - 1)*行间距; INT nHeight = it->rcChg.top + it->vtSubText.size()*fontSize.cy + it->nCellMargins * 2 + it->nLineSpacing*(it->vtSubText.size() - 1); while (nHeight > it->rcChg.bottom) { if (it->nTextFontSize < 0) { WriteTextLog("出错:固定区域文本字体缩小成负值仍无法显示"); break; } it->nTextFontSize--; SetTextFont(it->nTextFontSize, it->bTextBold, it->bTextItalic, it->strTextFontName); GetTextExtentPoint32(m_dcPrinter, it->strTextContent.c_str(), nTextlen, &fontSize); it->vtSubText.clear(); TextDownwards(it->strTextContent, it->rcChg.Width() - it->nCellMargins * 2, it->vtSubText); nHeight = it->rcChg.top + it->vtSubText.size()*fontSize.cy + it->nCellMargins * 2 + it->nLineSpacing*(it->vtSubText.size() - 1); } if (it->vtSubText.size()) it->strTextContent.clear(); } } // 注意:在最后一页时,需要再次重新计算; ////////////////////////////////////////////////////////////////////////// #endif // 将变化后的单元格设置为原始单元格; it = m_printlist.vtPrintCell.begin(); for (; it != m_printlist.vtPrintCell.end(); it++) { it->rcOrg = it->rcChg; } // 开始打印Json形成的表格; StartPrint(); StartPage(); // 画外围边框; INT nDrawResult = 0; if (m_printlist.bShowFrame) DrawRectange(m_printlist.rcPage, m_printlist.nLineWide, 2, 2, 2, 2); it = m_printlist.vtPrintCell.begin(); for (; it != m_printlist.vtPrintCell.end();) { nDrawResult = DrawCell(*it); if (nDrawResult == 0 || nDrawResult == 1) { // 保留; it++; } else if (nDrawResult == 2) { // 移除; it = m_printlist.vtPrintCell.erase(it); } } while (m_printlist.vtPrintCell.size()) { PrintChangePage(); } EndofPage(); EndofPrint(); return TRUE; } INT CEasyPrinterV1::DrawCell(IN STPrintCell & PrtCell) { // 是否换页; BOOL bChangePage = FALSE; // 画表格; INT nDrawResult = DrawRectange(PrtCell.rcChg, PrtCell.nLineWide, PrtCell.nLeftLineType, PrtCell.nTopLineType, PrtCell.nRightLineType, PrtCell.nBottomLineType); if (nDrawResult == 0) { // 未画,表示表格需要换页; return nDrawResult; } SIZE fontSize; if (PrtCell.nFillerType == 0) { // 输出文本; CRect rcText = PrtCell.rcChg; rcText.DeflateRect(PrtCell.nCellMargins, PrtCell.nCellMargins, PrtCell.nCellMargins, 0); SetTextFont(PrtCell.nTextFontSize, PrtCell.bTextBold, PrtCell.bTextItalic, PrtCell.strTextFontName); // 获取字高; if (PrtCell.vtSubText.size()) { GetTextExtentPoint32(m_dcPrinter, _T("1"), 1, &fontSize); INT nHeight = rcText.top + PrtCell.nLineSpacing + fontSize.cy; // 已输出文本高度; vector::iterator it = PrtCell.vtSubText.begin(); for (; it != PrtCell.vtSubText.end();) { // 输出文本之前,判断下一行是否到达底部; if (m_printlist.rcPage.bottom < nHeight) { // 换页的,不操作任何; it++; } else { // 输出文本的区域仍在底部上方,输出文本; GetTextExtentPoint32(m_dcPrinter, it->c_str(), it->length(), &fontSize); DrawText(*it, rcText, fontSize.cx, PrtCell.nTextAlignType); rcText.top += PrtCell.nLineSpacing + fontSize.cy; rcText.bottom = rcText.top + PrtCell.nLineSpacing + fontSize.cy; // 未换页的,移除掉; it = PrtCell.vtSubText.erase(it); nHeight = rcText.bottom; } } } else { if (PrtCell.strTextContent.length()) { GetTextExtentPoint32(m_dcPrinter, PrtCell.strTextContent.c_str(), PrtCell.strTextContent.length(), &fontSize); // 输出文本之前,判断显示区域能否完整容纳文本; if (m_printlist.rcPage.bottom < (rcText.top + fontSize.cy + PrtCell.nCellMargins * 2)) { // 无法输出文本; // 换页的,不操作任何; } else { DrawText(PrtCell.strTextContent, rcText, fontSize.cx, PrtCell.nTextAlignType); // 输出后,清空文本; PrtCell.strTextContent.clear(); } } } } else if (PrtCell.nFillerType == 1) {// 图片; TString strImageBase64 = PrtCell.strImgContent; BYTE *pImageBuffer = NULL; DWORD dwImageLength = 0; GetImgBufferFromBase64(PrtCell.strImgContent, &pImageBuffer, dwImageLength); Image *pImage = NULL; LoadImgFromBuffer(&pImage, pImageBuffer, dwImageLength); // 画图; Graphics graph(m_dcPrinter); graph.SetPageUnit(UnitPixel); graph.SetSmoothingMode(SmoothingModeHighQuality); RectF rf(PrtCell.rcOrg.left, PrtCell.rcOrg.top, PrtCell.rcOrg.Width(), PrtCell.rcOrg.Height()); graph.DrawImage(pImage, rf, 0, 0, pImage->GetWidth(), pImage->GetHeight(), UnitPixel); // 释放资源; if (pImageBuffer) delete[]pImageBuffer; if (pImage) delete pImage; } if (nDrawResult == 1) { PrtCell.bDrawHalf = TRUE; // 画一半,剩余部分需要换页; if (PrtCell.nFillerType == 0) {// 文本; INT nHeightGap = PrtCell.rcChg.bottom - m_printlist.rcPage.bottom; // 高度差; PrtCell.rcChg.top = PrtCell.rcChg.bottom - nHeightGap; } else if (PrtCell.nFillerType == 1) { // 如果填充物是图片,需要在画单元格外框时提前换页; TRACE("暂时未处理\n"); } } else if (nDrawResult == 2) { // 全画,未换页; TRACE("不需要处理\n"); } return nDrawResult; } /************************************************************************/ /* 函数:[3/14/2017 Jeff]; /* 描述:; /* 参数:; /* [IN] :; /* [OUT] :; /* [IN/OUT] :; /* 返回:void; /* 注意:; /* 示例:; /* /* 修改:; /* 日期:; /* 内容:; /************************************************************************/ void CEasyPrinterV1::PrintChangePage() { AutoChangePage(); // 画单元格; NewAnPage(); INT nDrawResult = 0; vector::iterator it = m_printlist.vtPrintCell.begin(); for (; it != m_printlist.vtPrintCell.end();) { nDrawResult = DrawCell(*it); if (nDrawResult == 0 || nDrawResult == 1) { // 保留; it++; } else if (nDrawResult == 2) { // 移除; it = m_printlist.vtPrintCell.erase(it); } } } /************************************************************************/ /* 函数:[3/14/2017 Jeff]; /* 描述:; /* 参数:; /* [IN] :; /* [OUT] :; /* [IN/OUT] :; /* 返回:void; /* 注意:; /* 示例:; /* /* 修改:; /* 日期:; /* 内容:; /************************************************************************/ void CEasyPrinterV1::AutoChangePage() { // 换页计算,偏移到下一页位置; INT nOffsetGap = m_printlist.rcPage.top - m_printlist.rcPage.bottom; vector::iterator it = m_printlist.vtPrintCell.begin(); for (; it != m_printlist.vtPrintCell.end(); it++) { // 所有单元格y坐标偏移nOffsetGap; if (it->bDrawHalf) { it->rcOrg.OffsetRect(0, nOffsetGap); it->rcOrg.top = m_printlist.rcPage.top; it->rcChg.OffsetRect(0, nOffsetGap); it->rcChg.top = m_printlist.rcPage.top; } else { it->rcOrg.OffsetRect(0, nOffsetGap); it->rcChg.OffsetRect(0, nOffsetGap); } } // 需要重新对文本框计算区域大小; it = m_printlist.vtPrintCell.begin(); for (; it != m_printlist.vtPrintCell.end(); it++) { if (it->nFillerType == 0) { if (it->vtSubText.size() != 0) {// 已经换过行的; SIZE fontSize; // 根据文本特性,计算出文本长度和高度; SetTextFont(it->nTextFontSize, it->bTextBold, it->bTextItalic, it->strTextFontName); GetTextExtentPoint32(m_dcPrinter, "1", 1, &fontSize); // 计算出新高; INT nHeight = it->vtSubText.size()*fontSize.cy + it->nCellMargins * 2 + it->nLineSpacing*(it->vtSubText.size() - 1); if (it->rcOrg.Height() < nHeight) { if (it->bAutoWraps) {// 字体固定,表格区域在适应字体; it->rcChg.bottom = it->rcChg.top + nHeight; } else {// 区域固定,字体要适应区域; do { SetTextFont(it->nTextFontSize--, it->bTextBold, it->bTextItalic, it->strTextFontName); GetTextExtentPoint32(m_dcPrinter, "1", 1, &fontSize); nHeight = it->vtSubText.size()*fontSize.cy + it->nCellMargins * 2 + it->nLineSpacing*(it->vtSubText.size() - 1); } while (it->rcOrg.Height() < nHeight); } } } } else if (it->nFillerType == 1) { TRACE("图片显示区域大小不需要改变\n"); } } CellTBTypesetting(); CellBBTypesetting(); }