使用 L_SaveFileOffset 保存多页 TIFF 文件
using L_SaveFileOffset to save a Multi-page TIFF file
我需要使用 L_SaveFileOffset
保存多页 TIFF 文件,因为我需要确保没有其他进程(包括 Windows 本身)可以在保存页面的过程中访问该文件,并且到目前为止据我所知,L_SaveFileOffset
是 LeadTools 中唯一允许使用文件句柄保存图像的 API。问题是,无论我做什么,都只会保存最后一页。请帮助。
HANDLE hFile = ::CreateFile(L"ColorMaps.tif", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if(NULL != hFile)
{
const wchar_t pathTemplate[] = {L"ColorMap%d.bmp"};
wchar_t tPath[sizeof(pathTemplate) / sizeof(pathTemplate[0])];
FILEINFO PageInfo;
SAVEFILEOPTION so;
LOADFILEOPTION tlo;
int i;
HDC hDc;
BITMAPHANDLE tBmp;
__int64 tSize;
memset(&tlo, 0, sizeof(LOADFILEOPTION));
tlo.uStructSize = sizeof(LOADFILEOPTION);
L_GetDefaultLoadFileOption(&tlo, sizeof(LOADFILEOPTION));
tlo.Flags |= ELO_ROTATED;
hDc = ::GetDC(NULL);
tlo.XResolution = ::GetDeviceCaps(hDc, LOGPIXELSX);
tlo.YResolution = ::GetDeviceCaps(hDc, LOGPIXELSY);
::ReleaseDC(NULL, hDc);
memset(&so, 0, sizeof(SAVEFILEOPTION));
so.uStructSize = sizeof(SAVEFILEOPTION);
so.Flags = ESO_INSERTPAGE;
memset(&tBmp, 0, sizeof(BITMAPHANDLE));
tBmp.uStructSize = sizeof(BITMAPHANDLE);
for(i = 1; i < 7; i++)
{
::StringCbPrintf(tPath, sizeof(tPath), pathTemplate, i);
L_FileInfo(tPath, &PageInfo, sizeof(FILEINFO), 0, &tlo);
L_LoadBitmap(tPath, &tBmp, sizeof(BITMAPHANDLE), 0, ORDER_RGBORGRAY, &tlo, &PageInfo);
if (TOP_LEFT != tBmp.ViewPerspective)
L_ChangeBitmapViewPerspective(NULL, &tBmp, sizeof(BITMAPHANDLE), TOP_LEFT);
L_SaveFileOffset((L_HFILE)hFile, 0, &tSize, &tBmp, FILE_TIF_PACKBITS, PageInfo.BitsPerPixel, 0, SAVEFILE_MULTIPAGE, NULL, NULL, &so);
so.PageNumber = i + 1;
}
::CloseHandle(hFile);
}
以上只是一个示例,可能有 1000 页被保存到 TIFF 文件中。
如果用户打开 Windows Explorer 并导航到保存文件的目录,您会看到 windows正在尝试在每个页面保存之间重新绘制文件的图标,如果我使用 L_SaveBitmap
或 L_SaveFile
,有时它们 return -14 因为 windows 正在读取文件并且 LeadTools 无法锁定它。
P.S。 L_SaveFileOffset
returns 1 (SUCCESS) 所有页面,我正在使用 LeadTools 文档映像版本 17.5.
谢谢
萨姆,
完全控制文件句柄的一种方法是使用重定向 IO。锁定整个 6 页的 TIFF 文件所需的代码如下所示:
// 2 global variables
L_HFILE hFileMyTiff = NULL;
bool reallyClose = false;
L_HFILE EXT_CALLBACK MyOpen(L_TCHAR* pFile, L_INT nMode, L_INT nShare, L_VOID* pUserData)
{
if(!hFileMyTiff) //only open the file if it's not already open
hFileMyTiff = (L_HFILE)::CreateFile(pFile, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
return hFileMyTiff;
}
L_UINT EXT_CALLBACK MyRead(L_HFILE FD, L_UCHAR * pBuf, L_UINT uCount, L_VOID *pUserData)
{
DWORD dwRead = 0;
::ReadFile(FD, pBuf, uCount, &dwRead, NULL);
return dwRead;
}
L_UINT EXT_CALLBACK MyWrite(L_HFILE FD, L_UCHAR * pBuf, L_UINT uCount, L_VOID* pUserData)
{
DWORD dwWritten = 0;
::WriteFile(FD, pBuf, uCount, &dwWritten, NULL);
return dwWritten;
}
L_SSIZE_T EXT_CALLBACK MySeek(L_HFILE FD, L_SSIZE_T nPos, L_INT nOrigin, L_VOID* pUserData)
{
return ::SetFilePointer(FD, nPos, NULL, nOrigin);
}
L_INT EXT_CALLBACK MyClose (L_HFILE FD, L_VOID* pUserData)
{
if(reallyClose)
{
::CloseHandle(FD);
hFileMyTiff = NULL;
}
else
::SetFilePointer(FD, 0, NULL, FILE_BEGIN);
return TRUE;
}
void tst()
{
const wchar_t pathTemplate[] = {L"ColorMap%d.bmp"};
wchar_t tPath[sizeof(pathTemplate) / sizeof(pathTemplate[0])];
FILEINFO PageInfo;
LOADFILEOPTION tlo;
int i;
HDC hDc;
BITMAPHANDLE tBmp;
__int64 tSize;
memset(&tlo, 0, sizeof(LOADFILEOPTION));
tlo.uStructSize = sizeof(LOADFILEOPTION);
L_GetDefaultLoadFileOption(&tlo, sizeof(LOADFILEOPTION));
tlo.Flags |= ELO_ROTATED;
hDc = ::GetDC(NULL);
tlo.XResolution = ::GetDeviceCaps(hDc, LOGPIXELSX);
tlo.YResolution = ::GetDeviceCaps(hDc, LOGPIXELSY);
::ReleaseDC(NULL, hDc);
memset(&tBmp, 0, sizeof(BITMAPHANDLE));
tBmp.uStructSize = sizeof(BITMAPHANDLE);
for(i = 1; i < 7; i++)
{
::StringCbPrintf(tPath, sizeof(tPath), pathTemplate, i);
L_FileInfo(tPath, &PageInfo, sizeof(FILEINFO), 0, &tlo);
L_LoadBitmap(tPath, &tBmp, sizeof(BITMAPHANDLE), 0, ORDER_RGBORGRAY, &tlo, &PageInfo);
if (TOP_LEFT != tBmp.ViewPerspective)
L_ChangeBitmapViewPerspective(NULL, &tBmp, sizeof(BITMAPHANDLE), TOP_LEFT);
if(i==6) //only allow closing after the last page is saved
reallyClose = true;
else
reallyClose = false;
L_RedirectIO(MyOpen, MyRead, MyWrite, MySeek, MyClose, NULL); //use our own file I/O functions
L_SaveFile(L"ColorMaps.tif", &tBmp, FILE_TIF_PACKBITS, PageInfo.BitsPerPixel, 0, SAVEFILE_MULTIPAGE, NULL, NULL, NULL);
L_RedirectIO(NULL, NULL, NULL, NULL, NULL, NULL); //reset to default I/O so as not affect loading
}
}
注意为简单起见使用了 2 个全局变量。一种更简洁的方法可能是定义您自己的数据结构并将其地址传递到 L_RedirectIO.
的 pUserData 参数中
我们已经使用 v17.5 测试了此解决方案并验证其工作正常。如果它不适合您的特定情况,请联系 LEADTOOLS 支持服务,我们将讨论其他替代方案。
更新:LEADTOOLS v19 的最新版本现在支持使用 L_SaveFileOffset() 函数将页面附加到 TIFF 文件。
我需要使用 L_SaveFileOffset
保存多页 TIFF 文件,因为我需要确保没有其他进程(包括 Windows 本身)可以在保存页面的过程中访问该文件,并且到目前为止据我所知,L_SaveFileOffset
是 LeadTools 中唯一允许使用文件句柄保存图像的 API。问题是,无论我做什么,都只会保存最后一页。请帮助。
HANDLE hFile = ::CreateFile(L"ColorMaps.tif", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if(NULL != hFile)
{
const wchar_t pathTemplate[] = {L"ColorMap%d.bmp"};
wchar_t tPath[sizeof(pathTemplate) / sizeof(pathTemplate[0])];
FILEINFO PageInfo;
SAVEFILEOPTION so;
LOADFILEOPTION tlo;
int i;
HDC hDc;
BITMAPHANDLE tBmp;
__int64 tSize;
memset(&tlo, 0, sizeof(LOADFILEOPTION));
tlo.uStructSize = sizeof(LOADFILEOPTION);
L_GetDefaultLoadFileOption(&tlo, sizeof(LOADFILEOPTION));
tlo.Flags |= ELO_ROTATED;
hDc = ::GetDC(NULL);
tlo.XResolution = ::GetDeviceCaps(hDc, LOGPIXELSX);
tlo.YResolution = ::GetDeviceCaps(hDc, LOGPIXELSY);
::ReleaseDC(NULL, hDc);
memset(&so, 0, sizeof(SAVEFILEOPTION));
so.uStructSize = sizeof(SAVEFILEOPTION);
so.Flags = ESO_INSERTPAGE;
memset(&tBmp, 0, sizeof(BITMAPHANDLE));
tBmp.uStructSize = sizeof(BITMAPHANDLE);
for(i = 1; i < 7; i++)
{
::StringCbPrintf(tPath, sizeof(tPath), pathTemplate, i);
L_FileInfo(tPath, &PageInfo, sizeof(FILEINFO), 0, &tlo);
L_LoadBitmap(tPath, &tBmp, sizeof(BITMAPHANDLE), 0, ORDER_RGBORGRAY, &tlo, &PageInfo);
if (TOP_LEFT != tBmp.ViewPerspective)
L_ChangeBitmapViewPerspective(NULL, &tBmp, sizeof(BITMAPHANDLE), TOP_LEFT);
L_SaveFileOffset((L_HFILE)hFile, 0, &tSize, &tBmp, FILE_TIF_PACKBITS, PageInfo.BitsPerPixel, 0, SAVEFILE_MULTIPAGE, NULL, NULL, &so);
so.PageNumber = i + 1;
}
::CloseHandle(hFile);
}
以上只是一个示例,可能有 1000 页被保存到 TIFF 文件中。
如果用户打开 Windows Explorer 并导航到保存文件的目录,您会看到 windows正在尝试在每个页面保存之间重新绘制文件的图标,如果我使用 L_SaveBitmap
或 L_SaveFile
,有时它们 return -14 因为 windows 正在读取文件并且 LeadTools 无法锁定它。
P.S。 L_SaveFileOffset
returns 1 (SUCCESS) 所有页面,我正在使用 LeadTools 文档映像版本 17.5.
谢谢
萨姆,
完全控制文件句柄的一种方法是使用重定向 IO。锁定整个 6 页的 TIFF 文件所需的代码如下所示:
// 2 global variables
L_HFILE hFileMyTiff = NULL;
bool reallyClose = false;
L_HFILE EXT_CALLBACK MyOpen(L_TCHAR* pFile, L_INT nMode, L_INT nShare, L_VOID* pUserData)
{
if(!hFileMyTiff) //only open the file if it's not already open
hFileMyTiff = (L_HFILE)::CreateFile(pFile, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
return hFileMyTiff;
}
L_UINT EXT_CALLBACK MyRead(L_HFILE FD, L_UCHAR * pBuf, L_UINT uCount, L_VOID *pUserData)
{
DWORD dwRead = 0;
::ReadFile(FD, pBuf, uCount, &dwRead, NULL);
return dwRead;
}
L_UINT EXT_CALLBACK MyWrite(L_HFILE FD, L_UCHAR * pBuf, L_UINT uCount, L_VOID* pUserData)
{
DWORD dwWritten = 0;
::WriteFile(FD, pBuf, uCount, &dwWritten, NULL);
return dwWritten;
}
L_SSIZE_T EXT_CALLBACK MySeek(L_HFILE FD, L_SSIZE_T nPos, L_INT nOrigin, L_VOID* pUserData)
{
return ::SetFilePointer(FD, nPos, NULL, nOrigin);
}
L_INT EXT_CALLBACK MyClose (L_HFILE FD, L_VOID* pUserData)
{
if(reallyClose)
{
::CloseHandle(FD);
hFileMyTiff = NULL;
}
else
::SetFilePointer(FD, 0, NULL, FILE_BEGIN);
return TRUE;
}
void tst()
{
const wchar_t pathTemplate[] = {L"ColorMap%d.bmp"};
wchar_t tPath[sizeof(pathTemplate) / sizeof(pathTemplate[0])];
FILEINFO PageInfo;
LOADFILEOPTION tlo;
int i;
HDC hDc;
BITMAPHANDLE tBmp;
__int64 tSize;
memset(&tlo, 0, sizeof(LOADFILEOPTION));
tlo.uStructSize = sizeof(LOADFILEOPTION);
L_GetDefaultLoadFileOption(&tlo, sizeof(LOADFILEOPTION));
tlo.Flags |= ELO_ROTATED;
hDc = ::GetDC(NULL);
tlo.XResolution = ::GetDeviceCaps(hDc, LOGPIXELSX);
tlo.YResolution = ::GetDeviceCaps(hDc, LOGPIXELSY);
::ReleaseDC(NULL, hDc);
memset(&tBmp, 0, sizeof(BITMAPHANDLE));
tBmp.uStructSize = sizeof(BITMAPHANDLE);
for(i = 1; i < 7; i++)
{
::StringCbPrintf(tPath, sizeof(tPath), pathTemplate, i);
L_FileInfo(tPath, &PageInfo, sizeof(FILEINFO), 0, &tlo);
L_LoadBitmap(tPath, &tBmp, sizeof(BITMAPHANDLE), 0, ORDER_RGBORGRAY, &tlo, &PageInfo);
if (TOP_LEFT != tBmp.ViewPerspective)
L_ChangeBitmapViewPerspective(NULL, &tBmp, sizeof(BITMAPHANDLE), TOP_LEFT);
if(i==6) //only allow closing after the last page is saved
reallyClose = true;
else
reallyClose = false;
L_RedirectIO(MyOpen, MyRead, MyWrite, MySeek, MyClose, NULL); //use our own file I/O functions
L_SaveFile(L"ColorMaps.tif", &tBmp, FILE_TIF_PACKBITS, PageInfo.BitsPerPixel, 0, SAVEFILE_MULTIPAGE, NULL, NULL, NULL);
L_RedirectIO(NULL, NULL, NULL, NULL, NULL, NULL); //reset to default I/O so as not affect loading
}
}
注意为简单起见使用了 2 个全局变量。一种更简洁的方法可能是定义您自己的数据结构并将其地址传递到 L_RedirectIO.
的 pUserData 参数中
我们已经使用 v17.5 测试了此解决方案并验证其工作正常。如果它不适合您的特定情况,请联系 LEADTOOLS 支持服务,我们将讨论其他替代方案。
更新:LEADTOOLS v19 的最新版本现在支持使用 L_SaveFileOffset() 函数将页面附加到 TIFF 文件。