【问题标题】:using L_SaveFileOffset to save a Multi-page TIFF file使用 L_SaveFileOffset 保存多页 TIFF 文件
【发布时间】:2016-10-31 22:21:58
【问题描述】:

我需要使用L_SaveFileOffset 保存多页 TIFF 文件,因为我需要确保在保存页面的过程中没有其他进程(包括 Windows 本身)可以访问该文件,据我所知 L_SaveFileOffsetLeadTools 中唯一用于保存的 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 资源管理器 并导航到正在保存文件的目录,则会出现问题,您可以看到 Windows 正在尝试在每个页面之间重新绘制文件的图标保存,如果我使用 L_SaveBitmapL_SaveFile,有时它们会返回 -14,因为 windows 正在读取文件并且 LeadTools 无法获得锁定它。

附: L_SaveFileOffset 为所有页面返回 1 (SUCCESS),我使用的是 LeadTools Documents 映像版本 17.5

谢谢

【问题讨论】:

    标签: c++ leadtools-sdk


    【解决方案1】:

    山姆,
    完全控制文件句柄的一种方法是使用重定向 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 文件也可以保存为嵌入文件或处理像我这样的情况?
    • 我们将调查函数的行为并与我们的开发团队讨论。如果您希望收到进度通知,请通过电子邮件或聊天打开支持案例并提及此帖子。
    • 你认为这也适用于 14.5 版吗?
    • 顺便问一下,每个线程我都必须调用L_RedirectIO吗?
    • 14.5 版具有类似的重定向 IO 功能,但某些数据类型不同。但是我们还没有用它测试过这个特定的代码,你应该记住,旧版本现在已经停产了。关于 L_RedirectIO,它是每个线程的。
    猜你喜欢
    • 1970-01-01
    • 2021-09-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多