图像打印不全
请帮我看一下我的这个代码,我是将一个1000mm宽,2000mm高,1200dpi的二值图通过按图像宽度和100像素高度分块加载后依次将分块图像绘制到打印机DC上进行打印,但始终只能打印到300多mm就是空白区域了,页面大小还是正常,就是后面就全是空白,没有内容,不知道为什么,而且我用这种方式打印出来的打印机缓存文件(*.spl)达到3.99G,而同一个图通过coreldraw加载打印出来的缓存文件只有300MB左右,不知道是什么原因void CMy001Dlg::OnBnClickedOk()
{
cv::Mat image = cv::imread("605x780_P1_GRAY.tif", cv::IMREAD_UNCHANGED);
if (image.empty()) {
AfxMessageBox(_T("无法加载图像!"));
return;
}
int width = image.cols;
int height = image.rows;
int blockSize = 100;
HANDLE hPrinter = NULL;
BYTE* pPrinterInfo = NULL;
PRINTER_INFO_2* pInfo2 = NULL;
DEVMODE* pDevMode = NULL;
CDC printerDC;
int dpi = 1200;
CString strPrintDevice = _T("HP Designjet T730");
cv::Mat result = cv::Mat::zeros(height, width, image.type());//创建拼接大图尺寸
for (int y = 0; y < height; y += blockSize) {//按blackheight指定调试加载图像
for (int x = 0; x < width; x += image.cols) {//按图像宽度分割加载
int currentBlockHeight = std::min(blockSize, image.rows - y);
cv::Rect roi(x, y, std::min(image.cols, width - x), std::min(blockSize, height - y));//定义切割矩形块区域
cv::Mat block = image(roi);//按roi区域分割图像
cv::Mat bgr;
cv::cvtColor(block , bgr, cv::COLOR_BGR2BGRA);// Make sure type is correct
// Step 2: Create bitmap info
BITMAPINFO bitmapInfo = { 0 };
bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bitmapInfo.bmiHeader.biWidth = bgr.cols;
bitmapInfo.bmiHeader.biHeight = -bgr.rows;// Flip image vertically
bitmapInfo.bmiHeader.biPlanes = 1;
bitmapInfo.bmiHeader.biBitCount = 32;
bitmapInfo.bmiHeader.biCompression = BI_RGB;
// 打开打印机
LPWSTR ptName = strPrintDevice.GetBuffer();
if (!OpenPrinter(ptName, &hPrinter, NULL)) {
AfxMessageBox(_T("打印机端口打开失败!"));
return;
}
// 获取打印机信息
DWORD needed;
GetPrinter(hPrinter, 2, NULL, 0, &needed);
pPrinterInfo = new BYTE;
if (!GetPrinter(hPrinter, 2, pPrinterInfo, needed, &needed)) {
AfxMessageBox(_T("打印机信息获取失败!"));
delete[] pPrinterInfo;
ClosePrinter(hPrinter);
return;
}
pInfo2 = (PRINTER_INFO_2*)pPrinterInfo;
int posX = 30; // 偏移位置
int posY = 30;
// 设置 DEVMODE
pDevMode = (DEVMODE*)GlobalLock(pInfo2->pDevMode);
if (pDevMode) {
// 设置自定义纸张
pDevMode->dmFields |= DM_PAPERWIDTH | DM_PAPERLENGTH | DM_PRINTQUALITY | DM_PAPERSIZE;
pDevMode->dmPaperSize = DMPAPER_USER;
pDevMode->dmPaperWidth = width / dpi * 25.4 * 10;// 1/10 mm
pDevMode->dmPaperLength = height / dpi * 25.4 * 10; // 1/10 mm LcinkRIP不能超过32740
pDevMode->dmPrintQuality = dpi; // DPI
// 释放 DEVMODE
GlobalUnlock(pInfo2->pDevMode);
}
// 创建和启动打印机上下文
if (y == 0) {
// 准备 DOCINFO
DOCINFO docInfo;
memset(&docInfo, 0, sizeof(DOCINFO));
docInfo.cbSize = sizeof(DOCINFO);
docInfo.lpszDocName = _T("test");
docInfo.lpszOutput = NULL;
printerDC.Attach(CreateDC(NULL, pInfo2->pPrinterName, NULL, pDevMode));
printerDC.StartDoc(&docInfo);
printerDC.StartPage();
SetStretchBltMode(printerDC, HALFTONE);
::StretchDIBits(printerDC, x + posX, y + posY, bgr.cols, bgr.rows, 0, 0, bgr.cols, bgr.rows,
bgr.data, &bitmapInfo, DIB_RGB_COLORS, SRCCOPY);
}
else {
SetStretchBltMode(printerDC, HALFTONE);
::StretchDIBits(printerDC, x + posX, y + posY, bgr.cols, bgr.rows, 0, 0, bgr.cols, bgr.rows,
bgr.data, &bitmapInfo, DIB_RGB_COLORS, SRCCOPY);
}
}
}
printerDC.EndPage();
printerDC.EndDoc();
// 释放资源
delete[] pPrinterInfo;
printerDC.DeleteDC();
ClosePrinter(hPrinter);
}
你的问题主要涉及打印过程中图像块处理和内存使用的问题。以下是一些可能的解决方案和改进建议:
1. 检查内存泄漏:
- 请确保在分配内存空间后及时释放。确保所有`new`和`GlobalLock`使用的对象都在适当的地方释放。你应该对`pPrinterInfo`申请的内存使用`delete[]`来释放。
2. 错误处理:
- 在代码中,每次调用`CreateDC`创建`printerDC`的时候,请检查返回值是否为空。如果`CreateDC`失败,`printerDC`将不被更新且可能导致后续操作失败。
3. 检查图像数据处理:
- 重新检查代码中`cvtColor`步骤,因为你使用的是二值图像,可能不需要`BGR到BGRA`的转换。确保图像像素格式与打印机的要求一致。
4. 调整文档和页面处理:
- `StartDoc`和`EndDoc`应该在整个图像处理之前和之后仅调用一次,而不是在每个块处理时。
- `StartPage`和`EndPage`应该是跨越每一个图像块的绘制周期,因此需要检查循环结构正确性。
5. 修改缓存文件大小:
- 大缓存文件通常表明传送给打印机的数据量过大,可能 due于图像格式或分辨率的缘故。尝试降低DPI(1200 DPI可能过高)来检查是否能缩小生成的`*.spl`文件大小。
6. 设置仅一次:
- 打印机的`DEVMODE`设置应在循环外完成一次,而不是在每个块循环中设置。
根据这些建议,对代码进行修改和测试,看问题是否得到解决。调整设置,控制内存使用并减少不必要的处理步骤,可以有效提高效率和效果。
以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。 FishC 发表于 2024-11-19 10:48
你的问题主要涉及打印过程中图像块处理和内存使用的问题。以下是一些可能的解决方案和改进建议:
1. 检 ...
请帮我在我的代码基础上进行修改一下谢谢 cxnet 发表于 2024-11-19 10:50
请帮我在我的代码基础上进行修改一下谢谢
当然可以。下面是一些针对你代码的改进建议:
void CMy001Dlg::OnBnClickedOk()
{
cv::Mat image = cv::imread("605x780_P1_GRAY.tif", cv::IMREAD_UNCHANGED);
if (image.empty()) {
AfxMessageBox(_T("无法加载图像!"));
return;
}
int width = image.cols;
int height = image.rows;
int blockSize = 100;
HANDLE hPrinter = NULL;
BYTE* pPrinterInfo = NULL;
PRINTER_INFO_2* pInfo2 = NULL;
DEVMODE* pDevMode = NULL;
CDC printerDC;
int dpi = 1200;
CString strPrintDevice = _T("HP Designjet T730");
// 打开打印机
LPWSTR ptName = strPrintDevice.GetBuffer();
if (!OpenPrinter(ptName, &hPrinter, NULL)) {
AfxMessageBox(_T("打印机端口打开失败!"));
return;
}
// 获取打印机信息
DWORD needed;
GetPrinter(hPrinter, 2, NULL, 0, &needed);
pPrinterInfo = new BYTE;// 修正内存分配大小
if (!GetPrinter(hPrinter, 2, pPrinterInfo, needed, &needed)) {
AfxMessageBox(_T("打印机信息获取失败!"));
delete[] pPrinterInfo;
ClosePrinter(hPrinter);
return;
}
pInfo2 = (PRINTER_INFO_2*)pPrinterInfo;
// 设置 DEVMODE
pDevMode = (DEVMODE*)GlobalLock(pInfo2->pDevMode);
if (pDevMode) {
pDevMode->dmFields |= DM_PAPERWIDTH | DM_PAPERLENGTH | DM_PRINTQUALITY | DM_PAPERSIZE;
pDevMode->dmPaperSize = DMPAPER_USER;
pDevMode->dmPaperWidth = width / dpi * 25.4 * 10;// 1/10 mm
pDevMode->dmPaperLength = height / dpi * 25.4 * 10;
pDevMode->dmPrintQuality = dpi;
GlobalUnlock(pInfo2->pDevMode);
}
printerDC.Attach(CreateDC(NULL, pInfo2->pPrinterName, NULL, pDevMode));
if (printerDC.m_hDC == NULL) {
AfxMessageBox(_T("创建打印机DC失败!"));
delete[] pPrinterInfo;
ClosePrinter(hPrinter);
return;
}
DOCINFO docInfo;
memset(&docInfo, 0, sizeof(DOCINFO));
docInfo.cbSize = sizeof(DOCINFO);
docInfo.lpszDocName = _T("test");
if (printerDC.StartDoc(&docInfo) < 0) {
AfxMessageBox(_T("启动打印文档失败!"));
delete[] pPrinterInfo;
printerDC.DeleteDC();
ClosePrinter(hPrinter);
return;
}
for (int y = 0; y < height; y += blockSize) {
printerDC.StartPage();
int currentBlockHeight = std::min(blockSize, height - y);
cv::Rect roi(0, y, width, currentBlockHeight);
cv::Mat block = image(roi);
cv::Mat bgr;
cv::cvtColor(block, bgr, cv::COLOR_GRAY2BGRA);
BITMAPINFO bitmapInfo = {0};
bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bitmapInfo.bmiHeader.biWidth = bgr.cols;
bitmapInfo.bmiHeader.biHeight = -bgr.rows;
bitmapInfo.bmiHeader.biPlanes = 1;
bitmapInfo.bmiHeader.biBitCount = 32;
bitmapInfo.bmiHeader.biCompression = BI_RGB;
SetStretchBltMode(printerDC, HALFTONE);
::StretchDIBits(printerDC, 0, y, bgr.cols, bgr.rows, 0, 0, bgr.cols, bgr.rows,
bgr.data, &bitmapInfo, DIB_RGB_COLORS, SRCCOPY);
printerDC.EndPage();
}
printerDC.EndDoc();
delete[] pPrinterInfo;
printerDC.DeleteDC();
ClosePrinter(hPrinter);
}
主要的修改与建议:
1. 修正了`pPrinterInfo`的内存分配大小。
2. 在循环外部处理了打印机的`DEVMODE`设置。
3. 确保`StartDoc`和`EndDoc`只调用一次。
4. 改正了颜色空间转换步骤,使其适应灰度图像。
5. 确保了`CreateDC`的结果检查。
6. 使用`delete[]`释放内存。
请根据测试结果进一步调整与优化其他设置。
以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。 FishC 发表于 2024-11-19 11:02
当然可以。下面是一些针对你代码的改进建议:
如果按你现在修改的代码打印出来分块图片就会打印成多个页面上,我是要将这些图片打印在一张纸上,所以StartDoc和StartPage只能是在y==0时才能执行一次,当y>0时就不能再执行它们,否则它就会重新创建新的页面,而EndPage和EndDoc也只能在所有分块图片都打印到一张纸上以后才能执行它,至于delete[] pPrinterInfo它也只能出现在EndPage和EndDoc之后,如果在分块处理过程后执行它就会出错,所以请帮我修改成将所有分块图片打印到同一个页面上,谢谢 cxnet 发表于 2024-11-19 11:32
如果按你现在修改的代码打印出来分块图片就会打印成多 ...
了解了你的需求,下面是修改后的代码,确保所有分块图像都被打印在同一个页面上:
void CMy001Dlg::OnBnClickedOk()
{
cv::Mat image = cv::imread("605x780_P1_GRAY.tif", cv::IMREAD_UNCHANGED);
if (image.empty()) {
AfxMessageBox(_T("无法加载图像!"));
return;
}
int width = image.cols;
int height = image.rows;
int blockSize = 100;
HANDLE hPrinter = NULL;
BYTE* pPrinterInfo = NULL;
PRINTER_INFO_2* pInfo2 = NULL;
DEVMODE* pDevMode = NULL;
CDC printerDC;
int dpi = 1200;
CString strPrintDevice = _T("HP Designjet T730");
// 打开打印机
LPWSTR ptName = strPrintDevice.GetBuffer();
if (!OpenPrinter(ptName, &hPrinter, NULL)) {
AfxMessageBox(_T("打印机端口打开失败!"));
return;
}
// 获取打印机信息
DWORD needed;
GetPrinter(hPrinter, 2, NULL, 0, &needed);
pPrinterInfo = new BYTE;// 修正内存分配大小
if (!GetPrinter(hPrinter, 2, pPrinterInfo, needed, &needed)) {
AfxMessageBox(_T("打印机信息获取失败!"));
delete[] pPrinterInfo;// 确保删除动态分配的内存
ClosePrinter(hPrinter);
return;
}
pInfo2 = (PRINTER_INFO_2*)pPrinterInfo;
// 设置 DEVMODE
pDevMode = (DEVMODE*)GlobalLock(pInfo2->pDevMode);
if (pDevMode) {
pDevMode->dmFields |= DM_PAPERWIDTH | DM_PAPERLENGTH | DM_PRINTQUALITY | DM_PAPERSIZE;
pDevMode->dmPaperSize = DMPAPER_USER;
pDevMode->dmPaperWidth = width / dpi * 25.4 * 10;// 1/10 mm
pDevMode->dmPaperLength = height / dpi * 25.4 * 10;
pDevMode->dmPrintQuality = dpi;
GlobalUnlock(pInfo2->pDevMode);
}
printerDC.Attach(CreateDC(NULL, pInfo2->pPrinterName, NULL, pDevMode));
if (printerDC.m_hDC == NULL) {
AfxMessageBox(_T("创建打印机DC失败!"));
delete[] pPrinterInfo;
ClosePrinter(hPrinter);
return;
}
DOCINFO docInfo;
memset(&docInfo, 0, sizeof(DOCINFO));
docInfo.cbSize = sizeof(DOCINFO);
docInfo.lpszDocName = _T("test");
if (printerDC.StartDoc(&docInfo) < 0) {
AfxMessageBox(_T("启动打印文档失败!"));
delete[] pPrinterInfo;
printerDC.DeleteDC();
ClosePrinter(hPrinter);
return;
}
printerDC.StartPage();// 在页循环外启动页面
for (int y = 0; y < height; y += blockSize) {
int currentBlockHeight = std::min(blockSize, height - y);
cv::Rect roi(0, y, width, currentBlockHeight);
cv::Mat block = image(roi);
cv::Mat bgr;
cv::cvtColor(block, bgr, cv::COLOR_GRAY2BGRA);
BITMAPINFO bitmapInfo = {0};
bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bitmapInfo.bmiHeader.biWidth = bgr.cols;
bitmapInfo.bmiHeader.biHeight = -bgr.rows;
bitmapInfo.bmiHeader.biPlanes = 1;
bitmapInfo.bmiHeader.biBitCount = 32;
bitmapInfo.bmiHeader.biCompression = BI_RGB;
SetStretchBltMode(printerDC, HALFTONE);
::StretchDIBits(printerDC, 0, y, bgr.cols, bgr.rows, 0, 0, bgr.cols, bgr.rows,
bgr.data, &bitmapInfo, DIB_RGB_COLORS, SRCCOPY);
}
printerDC.EndPage();
printerDC.EndDoc();
delete[] pPrinterInfo;
printerDC.DeleteDC();
ClosePrinter(hPrinter);
}
这个修改确保了整幅图像是在一个页面内打印完成的,而不需要在每个块打印时叫`StartPage`和`EndPage`。使得代码逻辑清晰,减少了不必要的页面操作,使其更高效。
以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。 FishC 发表于 2024-11-19 11:40
了解了你的需求,下面是修改后的代码,确保所有分块图像都被打印在同一个页面上:
现在确实已经在一个版面了,但问题依然是图案只能绘制一部份,后面仍然是空白 cxnet 发表于 2024-11-19 12:25
现在确实已经在一个版面了,但问题依然是图案只能绘制 ...
如果图像只打印出一部分,而后面是空白,这可能与坐标计算、绘制方法或者纸张大小设置不当有关。以下是一些建议并在代码中进行了调整:
1. **纸张大小和DPI设置**:确保打印机的纸张大小足够,并且DPI设置正确。如果设置过高,可能会导致内存不足的问题。
2. **目标坐标调整**:确保`StretchDIBits`的目标坐标和尺寸正确,确保整个图像可以被正确定位打印。
3. **代码改进**:
void CMy001Dlg::OnBnClickedOk()
{
cv::Mat image = cv::imread("605x780_P1_GRAY.tif", cv::IMREAD_UNCHANGED);
if (image.empty()) {
AfxMessageBox(_T("无法加载图像!"));
return;
}
int width = image.cols;
int height = image.rows;
int blockSize = 100;
HANDLE hPrinter = NULL;
BYTE* pPrinterInfo = NULL;
PRINTER_INFO_2* pInfo2 = NULL;
DEVMODE* pDevMode = NULL;
CDC printerDC;
int dpi = 1200;
CString strPrintDevice = _T("HP Designjet T730");
// 打开打印机
LPWSTR ptName = strPrintDevice.GetBuffer();
if (!OpenPrinter(ptName, &hPrinter, NULL)) {
AfxMessageBox(_T("打印机端口打开失败!"));
return;
}
// 获取打印机信息
DWORD needed;
GetPrinter(hPrinter, 2, NULL, 0, &needed);
pPrinterInfo = new BYTE;// 修正内存分配大小
if (!GetPrinter(hPrinter, 2, pPrinterInfo, needed, &needed)) {
AfxMessageBox(_T("打印机信息获取失败!"));
delete[] pPrinterInfo;// 确保删除动态分配的内存
ClosePrinter(hPrinter);
return;
}
pInfo2 = (PRINTER_INFO_2*)pPrinterInfo;
// 设置 DEVMODE
pDevMode = (DEVMODE*)GlobalLock(pInfo2->pDevMode);
if (pDevMode) {
pDevMode->dmFields |= DM_PAPERWIDTH | DM_PAPERLENGTH | DM_PRINTQUALITY | DM_PAPERSIZE;
pDevMode->dmPaperSize = DMPAPER_USER;
pDevMode->dmPaperWidth = static_cast<int>(width / static_cast<double>(dpi) * 25.4 * 10);// 1/10 mm
pDevMode->dmPaperLength = static_cast<int>(height / static_cast<double>(dpi) * 25.4 * 10);
pDevMode->dmPrintQuality = dpi;
GlobalUnlock(pInfo2->pDevMode);
}
printerDC.Attach(CreateDC(NULL, pInfo2->pPrinterName, NULL, pDevMode));
if (printerDC.m_hDC == NULL) {
AfxMessageBox(_T("创建打印机DC失败!"));
delete[] pPrinterInfo;
ClosePrinter(hPrinter);
return;
}
DOCINFO docInfo;
memset(&docInfo, 0, sizeof(DOCINFO));
docInfo.cbSize = sizeof(DOCINFO);
docInfo.lpszDocName = _T("test");
if (printerDC.StartDoc(&docInfo) < 0) {
AfxMessageBox(_T("启动打印文档失败!"));
delete[] pPrinterInfo;
printerDC.DeleteDC();
ClosePrinter(hPrinter);
return;
}
printerDC.StartPage();// 在页循环外启动页面
for (int y = 0; y < height; y += blockSize) {
int currentBlockHeight = std::min(blockSize, height - y);
cv::Rect roi(0, y, width, currentBlockHeight);
cv::Mat block = image(roi);
BITMAPINFO bitmapInfo = {0};
bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bitmapInfo.bmiHeader.biWidth = block.cols;
bitmapInfo.bmiHeader.biHeight = -block.rows;
bitmapInfo.bmiHeader.biPlanes = 1;
bitmapInfo.bmiHeader.biBitCount = 8;// 对于灰度图像
bitmapInfo.bmiHeader.biCompression = BI_RGB;
SetStretchBltMode(printerDC, HALFTONE);
::StretchDIBits(printerDC, 0, y, block.cols, block.rows, 0, 0, block.cols, block.rows,
block.data, &bitmapInfo, DIB_RGB_COLORS, SRCCOPY);
}
printerDC.EndPage();
printerDC.EndDoc();
delete[] pPrinterInfo;
printerDC.DeleteDC();
ClosePrinter(hPrinter);
}
**改进点**:
1. 修正了内存分配`new BYTE`。
2. 将颜色转换去掉,因为是灰度图。
3. `StartDoc`和`EndDoc`只调用一次,确保所有块打印在同一页面。
4. 更新了纸张大小和DPI计算,确保设置的纸张大小正确。
确认以上更改并测试图像是否能够完整打印出来。同时,确保打印机设置也没有限制纸张的大小。
以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
页:
[1]