其实gdiplus已经处理了很多东西和设置了,只可以由Cimage封装之后,很多东西不开放接口出来,结果处理起来很不方便,比如不能设置jpeg quality,会丢失exif信息等等。
没时间深究,随意整理了一个类,基本还算满足简单要求,对gdiplus的很多东西还很不清楚,只是一样画葫芦,总算保住一些信息。
还有很多东西可以追加和修改。看个人喜好,我本身很不喜欢读存文件操作,比较乐意关注算法的计算设计。将就能用就好,哈。
本来呢,我是想找个现成能用的,结果搜不到,闷。只好又为难自己。
私布以下代码好了。(在VC2005测试通过,实在懒得排版,要源文件的,可以留言索要,也可以花点时间自己整理一下,如果你有了好的修改版本,希望白送个给我,[email protected],谢谢)
/************************************************************
*
* [email protected] | kghcy.blog.163.com
* use as following:
* HImageFile cif;
* cif.Load(...);
* //here can get image information:
* //width, height, bpp, pBits etc. then to eidt
* cif.SetBits(...);
* cif.Save(...);
* no re-allocate cif, the result almostly reserve the source
* information, such as: exif.
* also can use cif.SetJpegQuality() save high quality jpeg
*
*************************************************************/
//HImageFile.h
#pragma once
#include <gdiplus.h>
#include <shlwapi.h>
#ifndef _ATL_NO_DEFAULT_LIBS
#pragma comment(lib, "shlwapi.lib")
#pragma comment(lib, "gdiplus.lib")
#endif
class HImageFile
{
public:
HImageFile(void);
~HImageFile(void);
public:
bool Load(const CString FileName);
bool Save(const CString FileName);
UINT GetBPP();
UINT GetWidth();
UINT GetHeight();
UINT GetPicth();
void* GetBits();
void SetWidth(UINT Width);
void SetHeight(UINT Height);
void SetPixelFormat(Gdiplus::PixelFormat PixelFormat);
void SetBits(void *pBits);
void SetJpegQuality(BYTE Quality);
private:
bool InitGdiplus();
void ReleaseGDIPlus();
void IncreaseCImageCount();
void DecreaseCImageCount();
private:
void *mpBits;
bool mIsDelBuf;
UINT mnBpp;
UINT mnWidth;
UINT mnPitch;
UINT mnHeight;
BYTE mnQuality;
Gdiplus::PixelFormat mPixelFormat;
UINT mnOldWidth;
UINT mnOldHeight;
Gdiplus::PixelFormat mOldPixelFormat;
///////use gdiplus//////////
Gdiplus::Bitmap *mpImg;
ULONG_PTR mdwToken;
CRITICAL_SECTION mSect;
LONG mnCImageObjects;
};
//HImageFile.cpp
#include "StdAfx.h"
#include "HImageFile.h"
HImageFile::HImageFile(void)
{
mnWidth = 0;
mnPitch = 0;
mnHeight = 0;
mnBpp = 0;
mpImg = NULL;
mpBits = NULL;
mnQuality = 90;
mIsDelBuf = false;
mdwToken = 0;
mnCImageObjects = 0;
InitializeCriticalSection(&mSect);
IncreaseCImageCount();
}
HImageFile::~HImageFile(void)
{
if(mpImg) { delete mpImg; mpImg = NULL; }
if(mIsDelBuf && mpBits) { delete[] mpBits; mpBits = NULL; }
DecreaseCImageCount();
DeleteCriticalSection(&mSect);
}
UINT HImageFile::GetBPP()
{
return mnBpp;
}
UINT HImageFile::GetWidth()
{
return mnWidth;
}
UINT HImageFile::GetPicth()
{
return mnPitch;
}
UINT HImageFile::GetHeight()
{
return mnHeight;
}
void* HImageFile::GetBits()
{
return mpBits;
}
void HImageFile::SetWidth(UINT Width)
{
mnWidth = Width;
}
void HImageFile::SetHeight(UINT Height)
{
mnHeight = Height;
}
void HImageFile::SetPixelFormat(Gdiplus::PixelFormat PixelFormat)
{
mPixelFormat = PixelFormat;
}
void HImageFile::SetBits(void *pBits)
{
if(mIsDelBuf && mpBits) { delete[] mpBits; mpBits = NULL; }
mIsDelBuf = false;
mpBits = pBits;
}
void HImageFile::SetJpegQuality(BYTE Quality)
{
mnQuality = Quality;
}
bool HImageFile::Load(const CString FileName)
{
if(!InitGdiplus())
return false;
if(mpImg) { delete mpImg; mpImg = NULL; }
mpImg = new Gdiplus::Bitmap(FileName);
if(!mpImg || mpImg->GetLastStatus() != Gdiplus::Ok)
return false;
/////////read image info////////////
mnWidth = mnOldWidth = mpImg->GetWidth();
mnHeight = mnOldHeight = mpImg->GetHeight();
mPixelFormat = mOldPixelFormat = mpImg->GetPixelFormat();
mnBpp = 0;
if(mPixelFormat & PixelFormatGDI)
mnBpp = Gdiplus::GetPixelFormatSize(mPixelFormat);
mnPitch = AtlAlignUp(mnWidth*mnBpp, 8)/8;
/////////read image data////////////
if(mIsDelBuf && mpBits)
delete[] mpBits;
mpBits = NULL;
mpBits = new BYTE [mnPitch*mnHeight];
if(!mpBits)
return false;
mIsDelBuf = true;
Gdiplus::BitmapData ImgData;
Gdiplus::Rect Roi(0, 0, mnWidth, mnHeight);
if(mpImg->LockBits(&Roi, Gdiplus::ImageLockModeRead, mPixelFormat, &ImgData) != Gdiplus::Ok)
return false;
BYTE *ptrD = (BYTE *)mpBits;
BYTE *ptrS = (BYTE *)ImgData.Scan0;
for(UINT j=0; j<mnHeight; j++)
{
memcpy(ptrD, ptrS, mnPitch);
ptrS += ImgData.Stride;
ptrD += mnPitch;
}
mpImg->UnlockBits(&ImgData);
return true;
}
bool HImageFile::Save(const CString FileName)
{
//////find image type///////
UINT nEncoders;
UINT nBytes;
Gdiplus::Status status;
status = Gdiplus::GetImageEncodersSize(&nEncoders, &nBytes);
if(status != Gdiplus::Ok)
return false;
USES_ATL_SAFE_ALLOCA;
Gdiplus::ImageCodecInfo* pEncoders = static_cast<Gdiplus::ImageCodecInfo*>(_ATL_SAFE_ALLOCA(nBytes, _ATL_SAFE_ALLOCA_DEF_THRESHOLD));
if(!pEncoders)
return false;
if(GetImageEncoders(nEncoders, nBytes, pEncoders) != Gdiplus::Ok)
return false;
CLSID clsidEncoder = CLSID_NULL;
CStringW strFileExt = ::PathFindExtensionW(FileName);
for(UINT icode = 0; clsidEncoder == CLSID_NULL && icode < nEncoders; icode++)
{
CStringW strExtList(pEncoders[icode].FilenameExtension);
int np = 0;
do{
CStringW strExt = ::PathFindExtensionW(strExtList.Tokenize(L";", np));
if(np != -1)
{
if(strExt.CompareNoCase(strFileExt) == 0)
{
clsidEncoder = pEncoders[icode].Clsid;
break;
}
}
}while(np != -1);
}
if(clsidEncoder == CLSID_NULL)
return false;
long nQuality = (long)mnQuality;
Gdiplus::EncoderParameters EncParams;
Gdiplus::EncoderParameter ep;
ep.Guid = Gdiplus::EncoderQuality;
ep.NumberOfValues = 1;
ep.Type = Gdiplus::EncoderParameterValueType::EncoderParameterValueTypeLong;
ep.Value = &nQuality;
EncParams.Count = 1;
EncParams.Parameter[0] = ep;
if(mnOldWidth != mnWidth || mnOldHeight != mnHeight || mOldPixelFormat != mPixelFormat)
{
if(!InitGdiplus())
return false;
mnPitch = AtlAlignUp(mnWidth*mnBpp, 8)/8;
if(mpImg) { delete mpImg; mpImg = NULL; }
mpImg = new Gdiplus::Bitmap(mnWidth, mnHeight, mnPitch, mPixelFormat, (BYTE*)mpBits);
if(!mpImg)
return false;
}
else//updata image data
{
Gdiplus::BitmapData ImgData;
Gdiplus::Rect Roi(0, 0, mnWidth, mnHeight);
if(mpImg->LockBits(&Roi, Gdiplus::ImageLockModeWrite, mPixelFormat, &ImgData) != Gdiplus::Ok)
return false;
BYTE *ptrS = (BYTE *)mpBits;
BYTE *ptrD = (BYTE *)ImgData.Scan0;
for(UINT j=0; j<mnHeight; j++)
{
memcpy(ptrD, ptrS, mnPitch);
ptrS += mnPitch;
ptrD += ImgData.Stride;
}
if(mpImg->UnlockBits(&ImgData) != Gdiplus::Ok)
return false;
}
return (mpImg->Save(FileName, &clsidEncoder, &EncParams) == Gdiplus::Ok);
}
////////////////////////////////
bool HImageFile::InitGdiplus()
{
EnterCriticalSection(&mSect);
bool bRet = true;
if(mdwToken == 0)
{
Gdiplus::GdiplusStartupInput Input;
Gdiplus::GdiplusStartupOutput Output;
bRet = Gdiplus::GdiplusStartup(&mdwToken, &Input, &Output) == Gdiplus::Ok;
}
LeaveCriticalSection(&mSect);
return bRet;
}
void HImageFile::ReleaseGDIPlus()
{
EnterCriticalSection(&mSect);
if(mdwToken)
Gdiplus::GdiplusShutdown(mdwToken);
mdwToken = 0;
LeaveCriticalSection(&mSect);
}
void HImageFile::IncreaseCImageCount()
{
EnterCriticalSection(&mSect);
mnCImageObjects++;
LeaveCriticalSection(&mSect);
}
void HImageFile::DecreaseCImageCount()
{
EnterCriticalSection(&mSect);
if(--mnCImageObjects == 0)
ReleaseGDIPlus();
LeaveCriticalSection(&mSect);
}