打印到TIFF, 图片打印机
源码: http://download.****.net/detail/kingmax54212008/9920964
如还有问题,请关注博主的其它打印驱动开发相关资料。或联系我的邮箱: [email protected]
介绍
我个人不是PDF的粉丝。对我来说,它不是“开放”,它是大的,通常你不能编辑它后。我们经常在这些PDF文件中收到文件,如工资单和纸币。对于我的管理,我最近做了一些努力,从纸到电脑。我想使用“开放标准”,如TIFF和HTML。PDF不合适。所以我需要一种将PDF转换成TIFF的方法。这就是这个代码。
背景
我搜索了一些时间找到一些代码或工具将PDF转换为TIFF。不幸的是,我只能找到商业产品。而且我不知道如果我买一个,那就做我想要的。所以我寻找办法自己去做。
PDF和TIFF之间有很大的区别。PDF文档被“渲染”,而TIFF只是一堆像素。这意味着如果您在PDF查看器中放大页面,它将保持清晰。另一方面,TIFF 图像的分辨率有限。当然,您可以在PDF文档上按Alt Print Screen,但是您的设备(显示器)的大部分不会得到更好的分辨率(像素数)。我没有找到一种方法让PDF查看器在设备上下文中比物理屏幕的设备上下文更大。幸运的是,微软提供了一个Print er驱动程序示例,更幸运的是,由于有一段时间您可以下载包含示例的Windows驱动程序工具包。虽然代码在用户模式下运行,但它是驱动程序。
使用打印机驱动程序,像素数量可能非常高。至少足以在正常页面上进行打印。此外,通过更改应用程序中的打印机属性,可以更改DPI,尺寸和颜色数量。更重要的是:只要应用程序可以打印,现在就可以将任何东西转换成TIFF 。
入门
Microsoft示例是一个工作驱动程序。它将页面打印到一个位图(.BMP)。使用TIFF的一个原因是一个文件可以包含多个页面。因此,代码必须添加到样本中以分别写入每个页面,并将其写入TIFF而不是BMP。
要开始使用,您必须获得Windows驱动程序工具包。按照以下步骤:
- 下载Windows驱动程序工具包。
- 它是一个ISO,所以你必须在CD刻录,或使用一些实用工具来安装图像。
- 安装WDK。确保选择了完整开发环境。
- 我建议将样本复制到您的代码的其余部分所在的地方(并且您定期备份,对吗?)。将<WinDDK-dir> \ src \ print \ oemdll \ bitmap复制到<your-dir> \ Bitmap_Driver(确保路径和名称中没有空格)!
-
做一个目录
Bitmap_Driver
,例如“Pack
”。这将是将驱动程序分发到CD / DVD / USB / HD / FD / ...的目录 -
将一些WinDDK文件从[...]
src \ print \
oemdll复制到新目录[...] \ Bitmap_Driver \ Pack:
- bitmap.gpd
- bitmap.inf
- bitmap.ini
- 在makefile.inc中,将第一行更改为“ INSTALLDIR =。\ Pack \ bitmap ”(不带引号)
- 现在您可以第一次构建示例。
构建驱动程序
正确的构建环境取决于计算机要使用它的位置。在开始菜单中,选择Windows驱动程序套件,WDK 7600。[...],Windows <您选择>,x <您选择>自由构建环境。这将打开一个具有正确设置的cmd框。在此框中,切换到您的Bitmap_Driver目录。然后键入“build”(不带引号)。您的驱动程序(bitmap.dll)将在Pack \ bitmap \ <架构>目录中。此路径在驱动程序文件中定义:bitmap.inf。
使用代码
现在是添加代码以使其写入多页TIFF的时候了。需要更改以下文件:bitmap.h,intrface.cpp,ddihook.cpp,precomp.h和源。
简而言之,这是打印时会发生什么:
-
COemUni2::EnablePDEV
- 初始化所有的东西 -
OEMStartPage
- 当新页面启动时调用的钩子 -
OEMSendPage
- 通常不会被调用。我们不使用它 -
COemUni2::ImageProcessing
- 每个数据块之后 -
COemUni2::FilterGraphics
- 我们不使用 -
OEMEndDoc
- 最后一页后。这里我们将数据发送到打印子系统 COemUni2::DisablePDEV
每一页都印在一个或多个部分。渲染的一部分之后,该方法在intrface.cpp被调用。该方法增加一个缓冲区并添加新的图形数据。该示例将挂起事件。在这个挂钩功能中,缓冲区被给予“ 打印子系统”,实际上它将写入您点击打印时指定的文件。COemUni2::ImageProcessing
OEMEndDoc
因为我们要写一个Multipage TIFF,所以我们需要收到一个新页面开始的通知。因此,我们要勾画OEMStartPage
。你可能会期望这样OEMSendPage
会更有意义,但事实证明它通常不会被调用。
static const> DRVFN s_aOemHookFuncs[] = {
{INDEX_DrvEndDoc, (PFN)OEMEndDoc},
{INDEX_DrvStartPage, (PFN) OEMStartPage},
{INDEX_DrvSendPage, (PFN) OEMSendPage}
};
当OEMStartPage
被调用时,我们正在开始一个新的页面。在这一刻,我们必须写上一页。
// --- Write the previous page - if exists --- if (pOemPDEV->pBufStart) { if (SaveFrame( pOemPDEV, pDevObj, false)) pOemPDEV->m_iframe+=1; }
然后启动一个新的:
// --- New page --- // Initializing private oempdev stuff pOemPDEV->bHeadersFilled = FALSE; pOemPDEV->bColorTable = FALSE; pOemPDEV->cbHeaderOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER); pOemPDEV->bmInfoHeader.biHeight = 0; pOemPDEV->bmInfoHeader.biSizeImage = 0; pOemPDEV->pBufStart = NULL; pOemPDEV->dwBufSize = 0;
SaveFrame
是将一个页面写入缓冲区的新功能。这里我们要把一些代码写入一个TIFF文件中的缓冲区。这个文件实际上是一个内存流,因为在最后(OEMEndDoc
)我们必须将数据直接传递给假脱机程序。
/*******************************************************\ * * Save Frame * \*******************************************************/ BOOL SaveFrame(POEMPDEV pOemPDEV, PDEVOBJ pdevobj, BOOL fClose) { INT cScans; Gdiplus::Bitmap* pbmp = NULL; //second+ frames: local bitmap log( L"SaveFrame"); // --- Number of scanlines --- cScans = pOemPDEV->bmInfoHeader.biHeight; // --- Flip the biHeight member so that it denotes top-down bitmap --- pOemPDEV->bmInfoHeader.biHeight = cScans * -1; BITMAPINFO* pbmpinf = (BITMAPINFO*) LocalAlloc( LPTR, sizeof(BITMAPINFOHEADER) + (pOemPDEV->cPalColors * sizeof(ULONG))); CopyMemory( &pbmpinf->bmiHeader, &pOemPDEV->bmInfoHeader, sizeof(BITMAPINFOHEADER)); if (pOemPDEV->bColorTable) { CopyMemory( &pbmpinf->bmiColors, pOemPDEV->prgbq, pOemPDEV->cPalColors*sizeof(RGBQUAD)); LocalFree(pOemPDEV->prgbq); } Gdiplus::Status sstat; log(L"init Gdiplus::Bitmap"); if (!pOemPDEV->m_pbmp) //Make Bitmap for the first time pOemPDEV->m_pbmp = new Gdiplus::Bitmap( pbmpinf, pOemPDEV->pBufStart); else //Second time: local bitmap pbmp = new Gdiplus::Bitmap( pbmpinf, pOemPDEV->pBufStart); if ((pOemPDEV->m_pbmp) || (pbmp)) { // --- Encoder Parameters --- Gdiplus::EncoderParameters* pEncoderParameters = (Gdiplus::EncoderParameters*) LocalAlloc( LPTR, sizeof(Gdiplus::EncoderParameters) + 2*sizeof(Gdiplus::EncoderParameter)); ULONG parameterValue0; ULONG parameterValue1; // An EncoderParameters object has an // array of EncoderParameter objects. pEncoderParameters->Count = 2; pEncoderParameters->Parameter[0].Guid = Gdiplus::EncoderCompression; pEncoderParameters->Parameter[0].Type = Gdiplus::EncoderParameterValueTypeLong; pEncoderParameters->Parameter[0].NumberOfValues = 1; pEncoderParameters->Parameter[0].Value = ¶meterValue0; pEncoderParameters->Parameter[1].Guid = Gdiplus::EncoderSaveFlag; pEncoderParameters->Parameter[1].Type = Gdiplus::EncoderParameterValueTypeLong; pEncoderParameters->Parameter[1].NumberOfValues = 1; pEncoderParameters->Parameter[1].Value = ¶meterValue1; //Black n White: CCITT4, else LZW if (pOemPDEV->bmInfoHeader.biBitCount == 1) parameterValue0 = Gdiplus::EncoderValueCompressionCCITT4; else parameterValue0 = Gdiplus::EncoderValueCompressionLZW; CLSID clsid; GetEncoderClsid(L"image/tiff", &clsid); log(L"Save (frame: %u)", pOemPDEV->m_iframe); if (pOemPDEV->m_iframe == 0) { //First frame parameterValue1 = Gdiplus::EncoderValueMultiFrame; pOemPDEV->m_pbmp->SetResolution( pdevobj->pPublicDM->dmPrintQuality, pdevobj->pPublicDM->dmYResolution); sstat = pOemPDEV->m_pbmp->Save( pOemPDEV->m_pstm, &clsid, pEncoderParameters); } else { //Second+ frame parameterValue1 = Gdiplus::EncoderValueFrameDimensionPage; //TODO: Necessary? pbmp->SetResolution( pdevobj->pPublicDM->dmPrintQuality, pdevobj->pPublicDM->dmYResolution); sstat = pOemPDEV->m_pbmp->SaveAdd( pbmp, pEncoderParameters); if (pbmp) delete [] pbmp; } if (sstat != Gdiplus::Ok) log(L"Bitmap-> Save failed (frame: %u)", pOemPDEV->m_iframe); if (fClose) { // Finishing: parameterValue1 = Gdiplus::EncoderValueFlush; sstat = pOemPDEV->m_pbmp->SaveAdd(pEncoderParameters); } LocalFree( pEncoderParameters); } else log(L"Couldn\'t make Gdiplus::Bitmap"); LocalFree( pbmpinf); return true; }
正如你所看到的,我们使用Gdiplus做这个工作。为什么我们在第一帧中使用成员变量作为位图,然后为以下帧使用局部变量?当我们要添加一个页面到第一个,我们使用一个方法在初始位图,所以我们必须重用那个。
要完整地关闭文件,在end(OEMEndDoc
)中,EncoderValueFlush
通过设置参数来指示函数的写入fClose
。
安装打印呃
现在让我们安装打印机,然后尝试一下。
- 添加本地打印呃
- 使用现有端口:FILE:(打印到文件)
- 有磁盘...
- 浏览到<your-dir> \ Bitmap_Driver \ Pack,然后选择bitmap.inf
- 如果这不是第一次:更换当前驱动程序
- 接下来,下一步,完成
现在打印一些新的打印呃。
如果你不能使它工作
记录
正如你可能已经注意到的,在某些点上,一行显示如下:
log(L"Bitmap->Save failed (frame: %u)", pOemPDEV->m_iframe);
因为它是一个驱动程序,你不能直接写入屏幕。另外,调试并不那么容易。这就是为什么我添加了一个函数来写消息使用OutputDebugStringW
。您可能知道,您必须做一些额外的工作才能使用Windows
7查看邮件:
- 使用RegEdit:导航到HKLM \ SYSTEM \ CurrentControlSet \ Control \ Session Manager \ Debug 打印过滤器
-
将DEFAULT的值更改为0xf(
REG_DWORD
) - 重启
-
您可以使用
DbgView
(以前的Sysinternals)查看消息,并选择“Capture Global Win32”
现在可以在代码中添加日志记录。
重新安装新版本后无更改
Windows从驱动程序缓存中选出相同的旧驱动程序。要安装新的,请更改bitmap.inf中的驱动程序版本,然后重新安装。现在新的驱动程序将被安装。
错误0x000003eb
如果您尝试安装驱动程序,将显示此错误。在这种情况下,文件bitmap.gpd可能会有错误。如果您更改了它,请尝试将其替换为原件。
兴趣点
由于Gdiplus用于保存文件,因此很容易将驱动程序保存为JPEG,GIF或其他类型的文件。事实上,它与更改行一样简单但是:其他格式不支持一个文件中的多个页面。所以,如果您需要另一种文件格式,最好从原始样本开始,然后添加代码以使用Gdiplus(in )保存文件。另外,检查源的依赖关系:“ gdiplus.lib ”和precomp.h:“gdiplus.h”GetEncoderClsid(L"image/tiff",
&clsid);
OEMEndDoc(...)
介绍
我个人不是PDF的粉丝。对我来说,它不是“开放”,它是大的,通常你不能编辑它后。我们经常在这些PDF文件中收到文件,如工资单和纸币。对于我的管理,我最近做了一些努力,从纸到电脑。我想使用“开放标准”,如TIFF和HTML。PDF不合适。所以我需要一种将PDF转换成TIFF的方法。这就是这个代码。
背景
我搜索了一些时间找到一些代码或工具将PDF转换为TIFF。不幸的是,我只能找到商业产品。而且我不知道如果我买一个,那就做我想要的。所以我寻找办法自己去做。
PDF和TIFF之间有很大的区别。PDF文档被“渲染”,而TIFF只是一堆像素。这意味着如果您在PDF查看器中放大页面,它将保持清晰。另一方面,TIFF 图像的分辨率有限。当然,您可以在PDF文档上按Alt Print Screen,但是您的设备(显示器)的大部分不会得到更好的分辨率(像素数)。我没有找到一种方法让PDF查看器在设备上下文中比物理屏幕的设备上下文更大。幸运的是,微软提供了一个Print er驱动程序示例,更幸运的是,由于有一段时间您可以下载包含示例的Windows驱动程序工具包。虽然代码在用户模式下运行,但它是驱动程序。
使用打印机驱动程序,像素数量可能非常高。至少足以在正常页面上进行打印。此外,通过更改应用程序中的打印机属性,可以更改DPI,尺寸和颜色数量。更重要的是:只要应用程序可以打印,现在就可以将任何东西转换成TIFF 。
入门
Microsoft示例是一个工作驱动程序。它将页面打印到一个位图(.BMP)。使用TIFF的一个原因是一个文件可以包含多个页面。因此,代码必须添加到样本中以分别写入每个页面,并将其写入TIFF而不是BMP。
要开始使用,您必须获得Windows驱动程序工具包。按照以下步骤:
- 下载Windows驱动程序工具包。
- 它是一个ISO,所以你必须在CD刻录,或使用一些实用工具来安装图像。
- 安装WDK。确保选择了完整开发环境。
- 我建议将样本复制到您的代码的其余部分所在的地方(并且您定期备份,对吗?)。将<WinDDK-dir> \ src \ print \ oemdll \ bitmap复制到<your-dir> \ Bitmap_Driver(确保路径和名称中没有空格)!
-
做一个目录
Bitmap_Driver
,例如“Pack
”。这将是将驱动程序分发到CD / DVD / USB / HD / FD / ...的目录 -
将一些WinDDK文件从[...]
src \ print \
oemdll复制到新目录[...] \ Bitmap_Driver \ Pack:
- bitmap.gpd
- bitmap.inf
- bitmap.ini
- 在makefile.inc中,将第一行更改为“ INSTALLDIR =。\ Pack \ bitmap ”(不带引号)
- 现在您可以第一次构建示例。
构建驱动程序
正确的构建环境取决于计算机要使用它的位置。在开始菜单中,选择Windows驱动程序套件,WDK 7600。[...],Windows <您选择>,x <您选择>自由构建环境。这将打开一个具有正确设置的cmd框。在此框中,切换到您的Bitmap_Driver目录。然后键入“build”(不带引号)。您的驱动程序(bitmap.dll)将在Pack \ bitmap \ <架构>目录中。此路径在驱动程序文件中定义:bitmap.inf。
使用代码
现在是添加代码以使其写入多页TIFF的时候了。需要更改以下文件:bitmap.h,intrface.cpp,ddihook.cpp,precomp.h和源。
简而言之,这是打印时会发生什么:
-
COemUni2::EnablePDEV
- 初始化所有的东西 -
OEMStartPage
- 当新页面启动时调用的钩子 -
OEMSendPage
- 通常不会被调用。我们不使用它 -
COemUni2::ImageProcessing
- 每个数据块之后 -
COemUni2::FilterGraphics
- 我们不使用 -
OEMEndDoc
- 最后一页后。这里我们将数据发送到打印子系统 COemUni2::DisablePDEV
每一页都印在一个或多个部分。渲染的一部分之后,该方法在intrface.cpp被调用。该方法增加一个缓冲区并添加新的图形数据。该示例将挂起事件。在这个挂钩功能中,缓冲区被给予“ 打印子系统”,实际上它将写入您点击打印时指定的文件。COemUni2::ImageProcessing
OEMEndDoc
因为我们要写一个Multipage TIFF,所以我们需要收到一个新页面开始的通知。因此,我们要勾画OEMStartPage
。你可能会期望这样OEMSendPage
会更有意义,但事实证明它通常不会被调用。
static const> DRVFN s_aOemHookFuncs[] = {
{INDEX_DrvEndDoc, (PFN)OEMEndDoc},
{INDEX_DrvStartPage, (PFN) OEMStartPage},
{INDEX_DrvSendPage, (PFN) OEMSendPage}
};
当OEMStartPage
被调用时,我们正在开始一个新的页面。在这一刻,我们必须写上一页。
// --- Write the previous page - if exists --- if (pOemPDEV->pBufStart) { if (SaveFrame( pOemPDEV, pDevObj, false)) pOemPDEV->m_iframe+=1; }
然后启动一个新的:
// --- New page --- // Initializing private oempdev stuff pOemPDEV->bHeadersFilled = FALSE; pOemPDEV->bColorTable = FALSE; pOemPDEV->cbHeaderOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER); pOemPDEV->bmInfoHeader.biHeight = 0; pOemPDEV->bmInfoHeader.biSizeImage = 0; pOemPDEV->pBufStart = NULL; pOemPDEV->dwBufSize = 0;
SaveFrame
是将一个页面写入缓冲区的新功能。这里我们要把一些代码写入一个TIFF文件中的缓冲区。这个文件实际上是一个内存流,因为在最后(OEMEndDoc
)我们必须将数据直接传递给假脱机程序。
/*******************************************************\ * * Save Frame * \*******************************************************/ BOOL SaveFrame(POEMPDEV pOemPDEV, PDEVOBJ pdevobj, BOOL fClose) { INT cScans; Gdiplus::Bitmap* pbmp = NULL; //second+ frames: local bitmap log( L"SaveFrame"); // --- Number of scanlines --- cScans = pOemPDEV->bmInfoHeader.biHeight; // --- Flip the biHeight member so that it denotes top-down bitmap --- pOemPDEV->bmInfoHeader.biHeight = cScans * -1; BITMAPINFO* pbmpinf = (BITMAPINFO*) LocalAlloc( LPTR, sizeof(BITMAPINFOHEADER) + (pOemPDEV->cPalColors * sizeof(ULONG))); CopyMemory( &pbmpinf->bmiHeader, &pOemPDEV->bmInfoHeader, sizeof(BITMAPINFOHEADER)); if (pOemPDEV->bColorTable) { CopyMemory( &pbmpinf->bmiColors, pOemPDEV->prgbq, pOemPDEV->cPalColors*sizeof(RGBQUAD)); LocalFree(pOemPDEV->prgbq); } Gdiplus::Status sstat; log(L"init Gdiplus::Bitmap"); if (!pOemPDEV->m_pbmp) //Make Bitmap for the first time pOemPDEV->m_pbmp = new Gdiplus::Bitmap( pbmpinf, pOemPDEV->pBufStart); else //Second time: local bitmap pbmp = new Gdiplus::Bitmap( pbmpinf, pOemPDEV->pBufStart); if ((pOemPDEV->m_pbmp) || (pbmp)) { // --- Encoder Parameters --- Gdiplus::EncoderParameters* pEncoderParameters = (Gdiplus::EncoderParameters*) LocalAlloc( LPTR, sizeof(Gdiplus::EncoderParameters) + 2*sizeof(Gdiplus::EncoderParameter)); ULONG parameterValue0; ULONG parameterValue1; // An EncoderParameters object has an // array of EncoderParameter objects. pEncoderParameters->Count = 2; pEncoderParameters->Parameter[0].Guid = Gdiplus::EncoderCompression; pEncoderParameters->Parameter[0].Type = Gdiplus::EncoderParameterValueTypeLong; pEncoderParameters->Parameter[0].NumberOfValues = 1; pEncoderParameters->Parameter[0].Value = ¶meterValue0; pEncoderParameters->Parameter[1].Guid = Gdiplus::EncoderSaveFlag; pEncoderParameters->Parameter[1].Type = Gdiplus::EncoderParameterValueTypeLong; pEncoderParameters->Parameter[1].NumberOfValues = 1; pEncoderParameters->Parameter[1].Value = ¶meterValue1; //Black n White: CCITT4, else LZW if (pOemPDEV->bmInfoHeader.biBitCount == 1) parameterValue0 = Gdiplus::EncoderValueCompressionCCITT4; else parameterValue0 = Gdiplus::EncoderValueCompressionLZW; CLSID clsid; GetEncoderClsid(L"image/tiff", &clsid); log(L"Save (frame: %u)", pOemPDEV->m_iframe); if (pOemPDEV->m_iframe == 0) { //First frame parameterValue1 = Gdiplus::EncoderValueMultiFrame; pOemPDEV->m_pbmp->SetResolution( pdevobj->pPublicDM->dmPrintQuality, pdevobj->pPublicDM->dmYResolution); sstat = pOemPDEV->m_pbmp->Save( pOemPDEV->m_pstm, &clsid, pEncoderParameters); } else { //Second+ frame parameterValue1 = Gdiplus::EncoderValueFrameDimensionPage; //TODO: Necessary? pbmp->SetResolution( pdevobj->pPublicDM->dmPrintQuality, pdevobj->pPublicDM->dmYResolution); sstat = pOemPDEV->m_pbmp->SaveAdd( pbmp, pEncoderParameters); if (pbmp) delete [] pbmp; } if (sstat != Gdiplus::Ok) log(L"Bitmap-> Save failed (frame: %u)", pOemPDEV->m_iframe); if (fClose) { // Finishing: parameterValue1 = Gdiplus::EncoderValueFlush; sstat = pOemPDEV->m_pbmp->SaveAdd(pEncoderParameters); } LocalFree( pEncoderParameters); } else log(L"Couldn\'t make Gdiplus::Bitmap"); LocalFree( pbmpinf); return true; }
正如你所看到的,我们使用Gdiplus做这个工作。为什么我们在第一帧中使用成员变量作为位图,然后为以下帧使用局部变量?当我们要添加一个页面到第一个,我们使用一个方法在初始位图,所以我们必须重用那个。
要完整地关闭文件,在end(OEMEndDoc
)中,EncoderValueFlush
通过设置参数来指示函数的写入fClose
。
安装打印呃
现在让我们安装打印机,然后尝试一下。
- 添加本地打印呃
- 使用现有端口:FILE:(打印到文件)
- 有磁盘...
- 浏览到<your-dir> \ Bitmap_Driver \ Pack,然后选择bitmap.inf
- 如果这不是第一次:更换当前驱动程序
- 接下来,下一步,完成
现在打印一些新的打印呃。
如果你不能使它工作
记录
正如你可能已经注意到的,在某些点上,一行显示如下:
log(L"Bitmap->Save failed (frame: %u)", pOemPDEV->m_iframe);
因为它是一个驱动程序,你不能直接写入屏幕。另外,调试并不那么容易。这就是为什么我添加了一个函数来写消息使用OutputDebugStringW
。您可能知道,您必须做一些额外的工作才能使用Windows
7查看邮件:
- 使用RegEdit:导航到HKLM \ SYSTEM \ CurrentControlSet \ Control \ Session Manager \ Debug 打印过滤器
-
将DEFAULT的值更改为0xf(
REG_DWORD
) - 重启
-
您可以使用
DbgView
(以前的Sysinternals)查看消息,并选择“Capture Global Win32”
现在可以在代码中添加日志记录。
重新安装新版本后无更改
Windows从驱动程序缓存中选出相同的旧驱动程序。要安装新的,请更改bitmap.inf中的驱动程序版本,然后重新安装。现在新的驱动程序将被安装。
错误0x000003eb
如果您尝试安装驱动程序,将显示此错误。在这种情况下,文件bitmap.gpd可能会有错误。如果您更改了它,请尝试将其替换为原件。
兴趣点
由于Gdiplus用于保存文件,因此很容易将驱动程序保存为JPEG,GIF或其他类型的文件。事实上,它与更改行一样简单但是:其他格式不支持一个文件中的多个页面。所以,如果您需要另一种文件格式,最好从原始样本开始,然后添加代码以使用Gdiplus(in )保存文件。另外,检查源的依赖关系:“ gdiplus.lib ”和precomp.h:“gdiplus.h”GetEncoderClsid(L"image/tiff",
&clsid);
OEMEndDoc(...)