优化从DIB加载图像功能,减少内存占用

This commit is contained in:
luoliangyi 2023-07-14 15:03:55 +08:00
parent 21ce2efb8e
commit 82d5c06e99
4 changed files with 207 additions and 64 deletions

View File

@ -99,7 +99,11 @@ HGBase_CreateImage
HGBase_CreateImageWithData HGBase_CreateImageWithData
HGBase_CreateImageFromData HGBase_CreateImageFromData
HGBase_CreateImageFromHBITMAP HGBase_CreateImageFromHBITMAP
HGBase_CreateImageFromDIB HGBase_CreateDIBFile
HGBase_CreateImageFromFile
HGBase_CreateDIBStream
HGBase_DestroyStream
HGBase_CreateImageFromStream
HGBase_CloneImage HGBase_CloneImage
HGBase_DestroyImage HGBase_DestroyImage
HGBase_GetImageData HGBase_GetImageData

View File

@ -2,6 +2,7 @@
#include "HGInc.h" #include "HGInc.h"
#if defined(HG_CMP_MSC) #if defined(HG_CMP_MSC)
#include <combaseapi.h> #include <combaseapi.h>
#include <atlstr.h>
#include <gdiplus.h> #include <gdiplus.h>
#endif #endif
@ -522,12 +523,10 @@ static HGResult LoadGdiImage(Gdiplus::Image* pImage, const HGImageRoi* roi, HGUI
return ret; return ret;
} }
if (HGBASE_IMGTYPE_BGR == type || HGBASE_IMGTYPE_BGRA == type) HBITMAP hBmp = NULL;
HGBase_GetHBITMAPOfImage(*image, &hBmp);
if (NULL != hBmp)
{ {
HBITMAP hBmp = NULL;
HGBase_GetHBITMAPOfImage(*image, &hBmp);
assert(NULL != hBmp);
HDC hMem = CreateCompatibleDC(NULL); HDC hMem = CreateCompatibleDC(NULL);
HBITMAP hOldBmp = (HBITMAP)SelectObject(hMem, hBmp); HBITMAP hOldBmp = (HBITMAP)SelectObject(hMem, hBmp);
Gdiplus::Graphics graphics(hMem); Gdiplus::Graphics graphics(hMem);
@ -539,9 +538,11 @@ static HGResult LoadGdiImage(Gdiplus::Image* pImage, const HGImageRoi* roi, HGUI
} }
else else
{ {
HGUInt type2 = HGBASE_IMGTYPE_BGR; HGUInt type2 = type;
if (HGBASE_IMGTYPE_RGBA == type) if (HGBASE_IMGTYPE_RGB == type)
type2 = HGBASE_IMGTYPE_BGRA; type2 = HGBASE_IMGTYPE_BGR;
else if (HGBASE_IMGTYPE_RGBA == type)
type2 = HGBASE_IMGTYPE_BGRA;
HGImage image2 = NULL; HGImage image2 = NULL;
ret = LoadGdiImage(pImage, roi, type2, origin, &image2); ret = LoadGdiImage(pImage, roi, type2, origin, &image2);
@ -565,62 +566,157 @@ static HGResult LoadGdiImage(Gdiplus::Image* pImage, const HGImageRoi* roi, HGUI
return ret; return ret;
} }
HGResult HGAPI HGBase_CreateImageFromDIB(HGLOBAL hMem, const HGImageRoi* roi, HGResult HGAPI HGBase_CreateDIBFile(HGLOBAL hMem, const HGChar *fileName)
{
if (NULL == hMem || NULL == fileName)
{
return HGBASE_ERR_INVALIDARG;
}
HGResult ret = HGBASE_ERR_FAIL;
ULONG size = (ULONG)GlobalSize(hMem);
void* pMem = GlobalLock(hMem);
if (NULL != pMem)
{
FILE *file = fopen(fileName, "wb");
if (NULL != file)
{
BITMAPINFOHEADER* infoHeader = (BITMAPINFOHEADER*)pMem;
DWORD bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
if (infoHeader->biBitCount <= 8)
bfOffBits += ((HGUInt)(1 << infoHeader->biBitCount) * sizeof(RGBQUAD));
BITMAPFILEHEADER fileHeader = { 0 };
fileHeader.bfType = 0x4D42;
fileHeader.bfSize = sizeof(BITMAPFILEHEADER) + size;
fileHeader.bfOffBits = bfOffBits;
fwrite(&fileHeader, 1, sizeof(BITMAPFILEHEADER), file);
fwrite(pMem, 1, size, file);
fclose(file);
ret = HGBASE_ERR_OK;
}
GlobalUnlock(hMem);
}
return ret;
}
HGResult HGAPI HGBase_CreateImageFromFile(const HGChar *fileName, const HGImageRoi* roi,
HGUInt type, HGUInt origin, HGImage* image)
{
if (NULL == fileName || NULL == image)
{
return HGBASE_ERR_INVALIDARG;
}
HGResult ret = HGBASE_ERR_FAIL;
ULONG_PTR nToken = 0;
Gdiplus::GdiplusStartupInput input;
Gdiplus::GdiplusStartupOutput output;
Gdiplus::GdiplusStartup(&nToken, &input, &output);
assert(0 != nToken);
CStringW fileName2(fileName);
Gdiplus::Image *img = new Gdiplus::Image(fileName2);
Gdiplus::Status status = img->GetLastStatus();
if (Gdiplus::Ok == status)
{
ret = LoadGdiImage(img, roi, type, origin, image);
}
delete img;
Gdiplus::GdiplusShutdown(nToken);
nToken = 0;
return ret;
}
HGResult HGAPI HGBase_CreateDIBStream(HGLOBAL hMem, HGStream *stream)
{
if (NULL == hMem || NULL == stream)
{
return HGBASE_ERR_INVALIDARG;
}
HGResult ret = HGBASE_ERR_FAIL;
ULONG size = (ULONG)GlobalSize(hMem);
void* pMem = GlobalLock(hMem);
if (NULL != pMem)
{
IStream* pStream = NULL;
HRESULT hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
if (SUCCEEDED(hr))
{
ULONG writeSize = 0;
BITMAPINFOHEADER* infoHeader = (BITMAPINFOHEADER*)pMem;
DWORD bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
if (infoHeader->biBitCount <= 8)
bfOffBits += ((HGUInt)(1 << infoHeader->biBitCount) * sizeof(RGBQUAD));
BITMAPFILEHEADER fileHeader = { 0 };
fileHeader.bfType = 0x4D42;
fileHeader.bfSize = sizeof(BITMAPFILEHEADER) + size;
fileHeader.bfOffBits = bfOffBits;
pStream->Write(&fileHeader, sizeof(BITMAPFILEHEADER), &writeSize);
pStream->Write(pMem, size, &writeSize);
*stream = (HGStream)pStream;
ret = HGBASE_ERR_OK;
}
GlobalUnlock(hMem);
}
return ret;
}
HGResult HGAPI HGBase_DestroyStream(HGStream stream)
{
if (NULL == stream)
{
return HGBASE_ERR_INVALIDARG;
}
IStream* pStream = (IStream*)stream;
pStream->Release();
return HGBASE_ERR_OK;
}
HGResult HGAPI HGBase_CreateImageFromStream(HGStream stream, const HGImageRoi* roi,
HGUInt type, HGUInt origin, HGImage* image) HGUInt type, HGUInt origin, HGImage* image)
{ {
if (NULL == hMem || NULL == image) if (NULL == stream || NULL == image)
{ {
return HGBASE_ERR_INVALIDARG; return HGBASE_ERR_INVALIDARG;
} }
HGResult ret = HGBASE_ERR_FAIL; HGResult ret = HGBASE_ERR_FAIL;
ULONG size = (ULONG)GlobalSize(hMem); ULONG_PTR nToken = 0;
void* pMem = GlobalLock(hMem); Gdiplus::GdiplusStartupInput input;
if (NULL != pMem) Gdiplus::GdiplusStartupOutput output;
{ Gdiplus::GdiplusStartup(&nToken, &input, &output);
IStream* pStream = NULL; assert(0 != nToken);
HRESULT hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
if (SUCCEEDED(hr))
{
ULONG writeSize = 0;
BITMAPINFOHEADER* infoHeader = (BITMAPINFOHEADER*)pMem; IStream* pStream = (IStream*)stream;
DWORD bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER); Gdiplus::Image *img = new Gdiplus::Image(pStream);
if (infoHeader->biBitCount <= 8) Gdiplus::Status status = img->GetLastStatus();
bfOffBits += ((HGUInt)(1 << infoHeader->biBitCount) * sizeof(RGBQUAD)); if (Gdiplus::Ok == status)
{
ret = LoadGdiImage(img, roi, type, origin, image);
}
BITMAPFILEHEADER fileHeader = { 0 }; delete img;
fileHeader.bfType = 0x4D42; Gdiplus::GdiplusShutdown(nToken);
fileHeader.bfSize = sizeof(BITMAPFILEHEADER) + size; nToken = 0;
fileHeader.bfOffBits = bfOffBits;
pStream->Write(&fileHeader, sizeof(BITMAPFILEHEADER), &writeSize);
pStream->Write(pMem, size, &writeSize);
ULONG_PTR nToken = 0; return ret;
Gdiplus::GdiplusStartupInput input;
Gdiplus::GdiplusStartupOutput output;
Gdiplus::GdiplusStartup(&nToken, &input, &output);
assert(0 != nToken);
Gdiplus::Image *img = new Gdiplus::Image(pStream);
Gdiplus::Status status = img->GetLastStatus();
if (Gdiplus::Ok == status)
{
ret = LoadGdiImage(img, roi, type, origin, image);
}
delete img;
Gdiplus::GdiplusShutdown(nToken);
nToken = 0;
pStream->Release();
}
GlobalUnlock(hMem);
}
return ret;
} }
#endif /* HG_CMP_MSC */ #endif /* HG_CMP_MSC */

View File

@ -8,6 +8,9 @@
#endif #endif
HG_DECLARE_HANDLE(HGImage); HG_DECLARE_HANDLE(HGImage);
#if defined(HG_CMP_MSC)
HG_DECLARE_HANDLE(HGStream);
#endif
/* 1位黑白图 */ /* 1位黑白图 */
#define HGBASE_IMGTYPE_BINARY 1L #define HGBASE_IMGTYPE_BINARY 1L
@ -120,11 +123,28 @@ HGEXPORT HGResult HGAPI HGBase_CreateImageFromData(HGByte* data, const HGImageIn
HGEXPORT HGResult HGAPI HGBase_CreateImageFromHBITMAP(HBITMAP hBmp, const HGImageRoi* roi, HGEXPORT HGResult HGAPI HGBase_CreateImageFromHBITMAP(HBITMAP hBmp, const HGImageRoi* roi,
HGUInt type, HGUInt origin, HGImage* image); HGUInt type, HGUInt origin, HGImage* image);
/* 从DIB内存创建新图像 /* 创建文件
*/
HGEXPORT HGResult HGAPI HGBase_CreateDIBFile(HGLOBAL hMem, const HGChar *fileName);
/* 从文件加载图像
*/
HGEXPORT HGResult HGAPI HGBase_CreateImageFromFile(const HGChar *fileName, const HGImageRoi* roi,
HGUInt type, HGUInt origin, HGImage* image);
/* 创建DIB流
*/
HGEXPORT HGResult HGAPI HGBase_CreateDIBStream(HGLOBAL hMem, HGStream *stream);
/* 销毁流
*/
HGEXPORT HGResult HGAPI HGBase_DestroyStream(HGStream stream);
/* 从流创建新图像
* : * :
* 1) hMem: in, DIB内存句柄 * 1) stream: in,
* 2) roi: DIB内存的感兴趣区域, NULL表示整个图像区域 * 2) roi: , NULL表示整个图像区域
* 3) type: in, , 0DIB内存最接近的type * 3) type: in, , 0type
* 4) origin: in, , * 4) origin: in, ,
* 5) image: out * 5) image: out
* : * :
@ -133,9 +153,9 @@ HGEXPORT HGResult HGAPI HGBase_CreateImageFromHBITMAP(HBITMAP hBmp, const HGImag
* 2) width=roi->right-roi->left; height=roi->bottom-roi->top; type=type; widthStep为4字节对齐; * 2) width=roi->right-roi->left; height=roi->bottom-roi->top; type=type; widthStep为4字节对齐;
* origin=origin * origin=origin
* 3) roi为{0, 0, width, height} * 3) roi为{0, 0, width, height}
* 4) xdpi=DIB的xDPI, ydpi=DIB的yDPI * 4) xdpi=xDPI, ydpi=yDPI
*/ */
HGEXPORT HGResult HGAPI HGBase_CreateImageFromDIB(HGLOBAL hMem, const HGImageRoi* roi, HGEXPORT HGResult HGAPI HGBase_CreateImageFromStream(HGStream stream, const HGImageRoi* roi,
HGUInt type, HGUInt origin, HGImage* image); HGUInt type, HGUInt origin, HGImage* image);
#endif /* HG_CMP_MSC */ #endif /* HG_CMP_MSC */
@ -388,4 +408,4 @@ HGEXPORT HGResult HGAPI HGBase_ReverseImage(HGImage image, HGImage destImage);
*/ */
HGEXPORT HGResult HGAPI HGBase_CopyImage(HGImage image, HGImage destImage); HGEXPORT HGResult HGAPI HGBase_CopyImage(HGImage image, HGImage destImage);
#endif /* __HGIMAGE_H__ */ #endif /* __HGIMAGE_H__ */

View File

@ -1,6 +1,7 @@
#include "HGTwainImpl.hpp" #include "HGTwainImpl.hpp"
#include "../base/HGInc.h" #include "../base/HGInc.h"
#include "../base/HGInfo.h" #include "../base/HGInfo.h"
#include "../base/HGUtility.h"
#include "app_cfg.h" #include "app_cfg.h"
std::map<HWND, HGTwainDSMImpl*> HGTwainDSMImpl::m_mapWnd; std::map<HWND, HGTwainDSMImpl*> HGTwainDSMImpl::m_mapWnd;
@ -964,8 +965,30 @@ HGResult HGTwainDSImpl::ImageNativeXfer(HGUInt type, HGUInt origin, HGImage* ima
return HGTWAIN_ERR_FAIL; return HGTWAIN_ERR_FAIL;
} }
HGResult ret = HGBase_CreateImageFromDIB(hMem, NULL, type, origin, image); #ifdef _WIN64
GlobalFree(hMem); HGStream stream = NULL;
HGResult ret = HGBase_CreateDIBStream(hMem, &stream);
GlobalFree(hMem);
if (HGBASE_ERR_OK != ret)
{
return ret;
}
ret = HGBase_CreateImageFromStream(stream, NULL, type, origin, image);
HGBase_DestroyStream(stream);
#else
HGChar tmpFile[260];
HGBase_GetTmpFileName("bmp", tmpFile, 260);
HGResult ret = HGBase_CreateDIBFile(hMem, tmpFile);
GlobalFree(hMem);
if (HGBASE_ERR_OK != ret)
{
return ret;
}
ret = HGBase_CreateImageFromFile(tmpFile, NULL, type, origin, image);
HGBase_DeleteFile(tmpFile);
#endif
return ret; return ret;
} }