优化从DIB加载图像功能,减少内存占用
This commit is contained in:
parent
21ce2efb8e
commit
82d5c06e99
|
@ -99,7 +99,11 @@ HGBase_CreateImage
|
|||
HGBase_CreateImageWithData
|
||||
HGBase_CreateImageFromData
|
||||
HGBase_CreateImageFromHBITMAP
|
||||
HGBase_CreateImageFromDIB
|
||||
HGBase_CreateDIBFile
|
||||
HGBase_CreateImageFromFile
|
||||
HGBase_CreateDIBStream
|
||||
HGBase_DestroyStream
|
||||
HGBase_CreateImageFromStream
|
||||
HGBase_CloneImage
|
||||
HGBase_DestroyImage
|
||||
HGBase_GetImageData
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include "HGInc.h"
|
||||
#if defined(HG_CMP_MSC)
|
||||
#include <combaseapi.h>
|
||||
#include <atlstr.h>
|
||||
#include <gdiplus.h>
|
||||
#endif
|
||||
|
||||
|
@ -522,12 +523,10 @@ static HGResult LoadGdiImage(Gdiplus::Image* pImage, const HGImageRoi* roi, HGUI
|
|||
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);
|
||||
HBITMAP hOldBmp = (HBITMAP)SelectObject(hMem, hBmp);
|
||||
Gdiplus::Graphics graphics(hMem);
|
||||
|
@ -539,9 +538,11 @@ static HGResult LoadGdiImage(Gdiplus::Image* pImage, const HGImageRoi* roi, HGUI
|
|||
}
|
||||
else
|
||||
{
|
||||
HGUInt type2 = HGBASE_IMGTYPE_BGR;
|
||||
if (HGBASE_IMGTYPE_RGBA == type)
|
||||
type2 = HGBASE_IMGTYPE_BGRA;
|
||||
HGUInt type2 = type;
|
||||
if (HGBASE_IMGTYPE_RGB == type)
|
||||
type2 = HGBASE_IMGTYPE_BGR;
|
||||
else if (HGBASE_IMGTYPE_RGBA == type)
|
||||
type2 = HGBASE_IMGTYPE_BGRA;
|
||||
|
||||
HGImage image2 = NULL;
|
||||
ret = LoadGdiImage(pImage, roi, type2, origin, &image2);
|
||||
|
@ -565,62 +566,157 @@ static HGResult LoadGdiImage(Gdiplus::Image* pImage, const HGImageRoi* roi, HGUI
|
|||
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)
|
||||
{
|
||||
if (NULL == hMem || NULL == image)
|
||||
if (NULL == stream || NULL == image)
|
||||
{
|
||||
return HGBASE_ERR_INVALIDARG;
|
||||
}
|
||||
|
||||
HGResult ret = HGBASE_ERR_FAIL;
|
||||
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;
|
||||
ULONG_PTR nToken = 0;
|
||||
Gdiplus::GdiplusStartupInput input;
|
||||
Gdiplus::GdiplusStartupOutput output;
|
||||
Gdiplus::GdiplusStartup(&nToken, &input, &output);
|
||||
assert(0 != nToken);
|
||||
|
||||
BITMAPINFOHEADER* infoHeader = (BITMAPINFOHEADER*)pMem;
|
||||
DWORD bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
|
||||
if (infoHeader->biBitCount <= 8)
|
||||
bfOffBits += ((HGUInt)(1 << infoHeader->biBitCount) * sizeof(RGBQUAD));
|
||||
IStream* pStream = (IStream*)stream;
|
||||
Gdiplus::Image *img = new Gdiplus::Image(pStream);
|
||||
Gdiplus::Status status = img->GetLastStatus();
|
||||
if (Gdiplus::Ok == status)
|
||||
{
|
||||
ret = LoadGdiImage(img, roi, type, origin, image);
|
||||
}
|
||||
|
||||
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);
|
||||
delete img;
|
||||
Gdiplus::GdiplusShutdown(nToken);
|
||||
nToken = 0;
|
||||
|
||||
ULONG_PTR nToken = 0;
|
||||
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;
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif /* HG_CMP_MSC */
|
||||
|
|
|
@ -8,6 +8,9 @@
|
|||
#endif
|
||||
|
||||
HG_DECLARE_HANDLE(HGImage);
|
||||
#if defined(HG_CMP_MSC)
|
||||
HG_DECLARE_HANDLE(HGStream);
|
||||
#endif
|
||||
|
||||
/* 1位黑白图 */
|
||||
#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,
|
||||
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内存句柄
|
||||
* 2) roi: DIB内存的感兴趣区域, NULL表示整个图像区域
|
||||
* 3) type: in, 新图像的类型, 0表示自动生成和DIB内存最接近的type
|
||||
* 1) stream: in, 流句柄
|
||||
* 2) roi: 流图像的感兴趣区域, NULL表示整个图像区域
|
||||
* 3) type: in, 新图像的类型, 0表示自动生成和流图像最接近的type
|
||||
* 4) origin: in, 新图像的数据排列方式, 必须指定
|
||||
* 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字节对齐;
|
||||
* 新图像的origin=origin
|
||||
* 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);
|
||||
|
||||
#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);
|
||||
|
||||
#endif /* __HGIMAGE_H__ */
|
||||
#endif /* __HGIMAGE_H__ */
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include "HGTwainImpl.hpp"
|
||||
#include "../base/HGInc.h"
|
||||
#include "../base/HGInfo.h"
|
||||
#include "../base/HGUtility.h"
|
||||
#include "app_cfg.h"
|
||||
|
||||
std::map<HWND, HGTwainDSMImpl*> HGTwainDSMImpl::m_mapWnd;
|
||||
|
@ -964,8 +965,30 @@ HGResult HGTwainDSImpl::ImageNativeXfer(HGUInt type, HGUInt origin, HGImage* ima
|
|||
return HGTWAIN_ERR_FAIL;
|
||||
}
|
||||
|
||||
HGResult ret = HGBase_CreateImageFromDIB(hMem, NULL, type, origin, image);
|
||||
GlobalFree(hMem);
|
||||
#ifdef _WIN64
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue