文章地址:http://www.codeproject.com/Articles/13559/ImageStone
ImageStone - 一个功能强大的C + +类库的图像处理
如何使用
ImageStone
STL和Boost库是一个只有头的C + +库,它是由完全的头文件,所以你就可以开始使用它只需添加#include “ImageStone.h”
在你的源代码的开始,但为了充分利用操作系统的功能,在各种平台之间存在一定的差异。
在Windows
只需要添加#include “ImageStone.h”,
在您的项目中,通常要附加在StdAfx.h中文件的末尾。
ImageStone
使用原始的Win32 GDI + API来实现图像的加载
/ 保存
功能,因此它具有高效率和小的最终文件大小。
在非Windows(UNIX,LINUX,Mac等等)
ImageStone
使用FreeImage的
解放来实现图像的加载/保存功能。
FreeImage的
从http://sourceforge.net/projects/freeimage/,然后编译它。- 包括
FreeImage的
头包括ImageStone
前。#include "FreeImage.h" #include "ImageStone.h"
- 现在你可以使用
ImageStone
。
先进的图像效果
为了减少编译时间,是不能被默认包含了很多很少使用的图像效果(浮雕,扭曲,波纹...),你可以通过以下方式使用:
#define IMAGESTONE_USE_EXT_EFFECT
#include "ImageStone.h"
... Load Image from File, Memory or Resource, Save Image to File
FCObjImage img ;
// from file
img.Load (L"test.jpg") ;
// from memory
img.Load (pMemory, nSize, IMG_JPG) ;
// from resource under windows
img.LoadBitmap (ID_BITMAP) ;
img.LoadResource (ID_JPG_FILE, _T("JPG"), IMG_JPG) ;
// save as jpg with quality 90 ( max is 100 )
img.Save (L"test.jpg", 90) ;
In order to better support for multiple languages, ImageStone
only supports wide char
filename, so you need to call a conversion function for ANSI filename.
std::wstring A_to_W (const char* p)
{
std::wstring ws ;
if (p)
{
setlocale (LC_CTYPE, "") ;
std::vector<wchar_t> buf (strlen(p)+1, 0) ;
mbstowcs (&buf[0], p, buf.size()-1) ;
ws = &buf[0] ;
}
return ws ;
}
FCObjImage img ;
img.Load (A_to_W("test.jpg").c_str()) ;
// under windows, you can use _bstr_t to implement conversion
img.Load (_bstr_t("test.jpg")) ;
... Load multi-page GIF
std::vector<FCObjImage*> frame_list ;
FCImageProperty prop ;
FCObjImage::Load (L"test.gif", frame_list, &prop) ;
// now frame_list store all frames of Gif image
// member m_frame_delay of prop store delay time between two frame
prop.m_frame_delay ;
// caller must delete all frames when them no longer be used
for (size_t i=0 ; i < frame_list.size() ; i++)
{
delete frame_list[i] ;
}
... Apply Image Effect
FCObjImage img ;
img.Load (L"test.jpg") ;
img.Stretch (200, 200) ;
img.Stretch_Smooth (500, 500) ;
FCEffectBlur_Gauss c1 (16, true) ;
img.ApplyEffect (c1) ;
FCEffectSplash c2 (20) ;
img.ApplyEffect (c2) ;
FCEffectMosaic c3 (20) ;
img.ApplyEffect (c3) ;
FCEffectBrightnessContrast c4 (30, 0) ;
img.ApplyEffect (c4) ;
You can monitor the progress of image processing by setting an observer:
// this monitor will stop image processing when user press ESC key
class CMyProgressMonitor : public FCProgressObserver
{
public:
virtual bool OnProgressUpdate (int nFinishPercentage)
{
MSG msg ;
if (PeekMessage (&msg, NULL, WM_KEYDOWN, WM_KEYDOWN, PM_REMOVE) &&
(msg.wParam == VK_ESCAPE))
{
return false ;
}
return true ;
}
};
// apply effect with progress monitor
FCObjImage img ;
img.Load (L"test.jpg") ;
CMyProgressMonitor aProgress ;
FCEffectMosaic c1 (20) ;
img.ApplyEffect (c1, &aProgress) ;
... Custom Image Effect
// create our effect : split RGB channel of image
class CEffectSplitChannel : public FCImageEffect
{
public:
FCObjImage m_red, m_green, m_blue ;
private:
virtual bool IsSupport (const FCObjImage& img)
{
return img.IsValidImage() && (img.ColorBits() >= 24) ;
}
virtual void OnBeforeProcess (FCObjImage& img)
{
int w = img.Width() ;
int h = img.Height() ;
m_red.Create (w, h, 24) ;
m_green.Create (w, h, 24) ;
m_blue.Create (w, h, 24) ;
}
virtual void ProcessPixel (FCObjImage& img, int x, int y, BYTE* pPixel)
{
PCL_R(m_red.GetBits(x,y)) = PCL_R(pPixel) ;
PCL_G(m_green.GetBits(x,y)) = PCL_G(pPixel) ;
PCL_B(m_blue.GetBits(x,y)) = PCL_B(pPixel) ;
}
};
// test, save RGB channel to image
void Test()
{
FCObjImage img ;
img.Load (L"test.jpg") ;
CEffectSplitChannel cmd ;
img.ApplyEffect (cmd) ;
cmd.m_red.Save (L"red.jpg") ;
cmd.m_green.Save (L"green.jpg") ;
cmd.m_blue.Save (L"blue.jpg") ;
}
... Read and Modify EXIF (Win Only)
FCObjImage img ;
FCImageProperty prop ;
img.Load (L"d:\\test.jpg", &prop) ;
// modify manufacturer of the equipment
prop.m_EquipMake = "PhoXo" ;
// modify the date of photograph
prop.m_ExifDTOrig = "2011:11:26 09:26:00" ;
std::vector<std::string> & ls = prop.m_other_gdiplus_prop ;
for (size_t i=0 ; i < ls.size() ; i++)
{
Gdiplus::PropertyItem it = FCImageCodec_Gdiplus::ReferencePropertyBuffer (ls[i]) ;
// modify ISO speed to 400
if (it.id == PropertyTagExifISOSpeed)
{
short nISO = 400 ;
ls[i] = FCImageCodec_Gdiplus::CreatePropertyBuffer(it.id, it.type, 2, &nISO) ;
}
}
// save image file with modified EXIF
img.Save (L"d:\\test.jpg", prop) ;
... Draw Image (Win Only)
FCObjImage img ;
img.Load (L"c:\\test.png") ;
// for 32bpp image, method Draw use Win32 API AlphaBlend to draw,
// so we need pre-multiply alpha before draw
// for <= 24bpp image, method Draw use Win32 API BitBlt to draw
if (img.ColorBits() == 32)
{
img.ApplyEffect (FCEffectPremultipleAlpha()) ;
}
// Draw whole image (no stretch) on point(0,0) of hdc
img.Draw (hdc, 0, 0) ;
// Draw whole image on specified region of hdc.
RECT rcOnDC = {100, 100, 200, 200} ;
img.Draw (hdc, rcOnDC) ;
// Draw region of image on specified region of hdc.
RECT rcOnImage = {20, 20, 50, 50} ;
img.Draw (hdc, rcOnDC, &rcOnImage) ;
// Draw whole image in window.
SIZE img_size = {img.Width(), img.Height()} ;
RECT rcWindow = {0, 0, 500, 500} ;
RECT rc = FCObjImage::CalcFitWindowSize(img_size, rcWindow) ;
img.Draw (hdc, rc) ;
Although BitBlt is faster than AlphaBlend, it will destroy the alpha channel of destination. Some features such as: layered window, DWM need alpha channel, so these cases we have to convert image to 32bpp, using AlphaBlend to draw.
... Convert between HBITMAP and Gdiplus::Bitmap (Win Only)
FCObjImage img ;
// FCObjImage can be converted to HBITMAP automatically, and can be selected into HDC
SelectObject (hdc, img) ;
// create image based on HBITMAP
img.FromHBITMAP (hBitmap) ;
// create Gdiplus::Bitmap, caller must delete returned bitmap
Gdiplus::Bitmap * pBmp = img.CreateBitmap() ;
if (pBmp)
delete pBmp ;
// create image based on Gdiplus::Bitmap
Gdiplus::Bitmap gpBmp (L"c:\\test.jpg") ;
img.FromBitmap (gpBmp) ;
... Add Text on Image (Win Only)

void DrawText (HDC dc)
{
// GDI draw text
SetTextColor (dc, RGB(0,0,255)) ;
TextOut (dc, 0, 0, _T("PhoXo"), 5) ;
// GDI+ draw text
Gdiplus::Graphics g(dc) ;
g.SetSmoothingMode (Gdiplus::SmoothingModeAntiAlias) ;
g.SetInterpolationMode (Gdiplus::InterpolationModeHighQualityBicubic) ;
Gdiplus::FontFamily ffami (L"Arial") ;
Gdiplus::StringFormat fmt ;
Gdiplus::GraphicsPath str_path ;
str_path.AddString (L"PhoXo", -1, &ffami,
Gdiplus::FontStyleBold, 48, Gdiplus::Point(20,20), &fmt) ;
Gdiplus::Pen gp (Gdiplus::Color(0,0,160), 8) ;
gp.SetLineJoin (Gdiplus::LineJoinRound) ;
Gdiplus::Rect rc (20, 20, 30, 60) ;
Gdiplus::Color cStart (255,255,255) ;
Gdiplus::Color cEnd (0,128,255) ;
Gdiplus::LinearGradientBrush gb (rc, cStart, cEnd,
Gdiplus::LinearGradientModeVertical) ;
g.DrawPath (&gp, &str_path) ;
g.FillPath (&gb, &str_path) ;
}
void Test()
{
FCObjImage img ;
img.Create (300, 200, 24) ;
// fill back grid
img.ApplyEffect (FCEffectFillGrid(FCColor(192,192,192), FCColor(255,255,255), 16)) ;
DrawText (FCImageDrawDC(img)) ;
img.Save (L"d:\\test.png") ;
}
... Using in DLL (Win Only)
In most cases, there is no difference on using between in DLL and in client:
extern "C" __declspec(dllexport) HBITMAP LoadFileToDDB (LPCWSTR sFilename)
{
FCObjImage img ;
img.Load (sFilename) ;
HDC screen_dc = GetDC(NULL) ;
HBITMAP hBmp = CreateCompatibleBitmap(screen_dc, img.Width(), img.Height()) ;
ReleaseDC (NULL, screen_dc) ;
img.Draw (FCImageDrawDC(hBmp), 0, 0) ;
return hBmp ;
}
But, if you want to call Load
or Save
method of FCObjImage
in DllMain
or constructor of global object in DLL, you need use FCAutoInitGDIPlus
to init GDI+ module in your clients before load DLL, and disable auto GDI+ init ofImageStone
in DLL.
// call Load in global object.
class CGlobalObj
{
public:
CGlobalObj()
{
FCImageCodec_Gdiplus::AUTO_INIT_GDIPLUS() = FALSE ;
FCObjImage img ;
img.Load (L"c:\\test.jpg") ;
}
};
CGlobalObj g_obj ;
// call Load in DllMain.
BOOL APIENTRY DllMain (HMODULE hModule, DWORD, LPVOID)
{
FCImageCodec_Gdiplus::AUTO_INIT_GDIPLUS() = FALSE ;
FCObjImage img ;
img.Load (L"c:\\test.jpg") ;
return TRUE ;
}
... Miscellaneous Function (Win Only)
FCObjImage img ;
// capture current screen
HDC screen_dc = GetDC(NULL) ;
RECT rc = {0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN)} ;
img.CaptureDC (screen_dc, rc) ;
ReleaseDC (NULL, screen_dc) ;
// copy this image to clipboard
img.CopyToClipboard() ;
// get image in clipboard
img.GetClipboard() ;
// convert image to HRGN
img.ApplyEffect (FCEffectThreshold(128)) ;
::SetWindowRgn (hWnd, img.CreateHRGN(), TRUE) ;
History
- 2011 - 11 - 27, V7.0
+ Code Refactoring, more features, more efficient, more easier to use - 2007 - 03 - 11, V4.0
+ AddFCPixelFillGradientFrame
+ AddFCPixelLensFlare
/FCPixelTileReflection
/FCPixelSoftGlow
effect
* Modify example
* ImproveFCObjImage::AlphaBlend
* ModifyFCPixelBlinds
* Modify brightness/contrast/hue/saturation/emboss
* Rewrite gauss blur processor
- RemoveFCPixelDeinterlace
- RemoveFCPixelAddRandomNoise
- RemoveFCPixelFill3DSolidFrame
- RemoveFCImageHandleFactory_IJL15
andFCImageHandle_IPicture
- 2006 - 10 - 25, V3.0
* ImproveFCImageHandle_Gdiplus
class to load multi-frame gif/tiff image and load jpeg's EXIF information
* ImproveFCImageHandle_FreeImage
class to save gif with transparency color
* ChangeFCPixelHueSaturation
's hue arithmetic
* ChangeFCPixelColorTone
's arithmetic, more look like old photo
* Change innerFCImageHandleBase
interface, it's never mind for user
* Substitutestd::fstream
by ANSI C file function, because of a bug in VC2005
+ AddFCImageProperty
to store image's property, functionFCObjImage::Load
andFCObjImage::Save
support it
+ Add example 010: Load jpeg's EXIF information via GDI+
- RemoveFCObjImage::GetNextFrameDelay
andFCObjImage::SetNextFrameDelay
, you can get them fromFCImageProperty
- 2006 - 09 - 07, V2.0
+ More mature - 2006 - 03 - 11, V1.0
+ Initial version
License
This article, along with any associated source code and files, is licensed under The zlib/libpng License
About the Author
![]() | crazybit
Team Leader
PhoXo
China
![]()
Member
|