VC++图像存取总结
生活随笔
收集整理的這篇文章主要介紹了
VC++图像存取总结
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
使用GDI+的MFC應用程序的文件打開和保存對話框
文章概要:CGdiplusFileOpenDialog和CGdiplusFileSaveAsDialog類提供了一個
在GDI+的MFC應用程序輕松實現文件打開和保存對話框的方法。 主要特點是:?
它們可以動態地裝入關于支持圖像的解碼器/編碼器和構建文件過濾清單。 它們
可以獲得當前圖像編碼器標識碼(CLSID)以供需要將其作為一個參數的GDI+函
數使用。 它們可以檢查和驗證文件名和擴展名。
(譯注:原文代碼的Demo_VC7沒有在同Demo_VC6一樣顯示滾動條視圖,修改之)
開發環境:Windows XP/Server 2003/2000/NT4.0-SP6/98/Me, MS Visual Sudio?
6.0/2003, GDI+
介紹
CGdiplusFileOpenDialog和CGdiplusFileSaveAsDialog類提供了一個在GDI+的
MFC應用程序輕松實現文件打開和保存對話框的方法。
主要特點是:
它們可以動態地裝入關于支持圖像的解碼器/編碼器和構建文件過濾清單。
它們可以獲得當前圖像編碼器標識碼(CLSID)以供需要將其作為一個參數的
GDI+函數使用。
它們可以檢查和驗證文件名和擴展名。
你可以在類的描述和demo應用程序中找到更多的詳情。
(類的)層次表
CGdiplusFileDialog類
CGdiplusFileDialog繼承于MFC CFileDialog類,同時也是
CGdiplusFileOpenDialog和CGdiplusFileSaveAsDialog的抽象基類。
封裝一個包含所支持的解碼器/編碼器的數組(m_arrCodecInfo)
實現基函數TranslateFilter:轉換一個MFC-like文件過濾器(使用一個''|''作
為分隔符)到一個OPENFILENAME結構文件過濾器(使用''\0''作為分隔符)
聲明兩個純虛函數:FillCodecInfoArray 和ConstructMFCStyleFilte;在派生
類中,覆寫函數實現特定操作。
覆寫CFileDialog::DoModal;在調用基類函數之前調用,它
o 檢查GDI+庫是否被初始化
o 調用FillCodecInfoArray、 ConstructMFCStyleFilter 和 TranslateFilter
函數
CGdiplusFileOpenDialog類
CGdiplusFileOpenDialog實現文件打開命令對話框。
覆寫CGdiplusFileDialog::FillCodecInfoArray并調用
Gdiplus::GetImageDecoders填充關于可用譯碼器的信息數組。
o 文件格式的名稱(如:"JPEG")
o 已用擴展名(如:"*.JPG、*.JPEG、*.JPE、*.JFIF")
o 在打開對話框(譯注:原文為Save As dialog,應該是Open dialog,筆誤了
)中使用的缺省擴展名(如:"JPG")
o 解碼器標識碼
覆寫CGdiplusFileDialog::ConstructMFCStyleFilter構建一個"MFC 樣式"的過
濾器(使用一個''|''作為分隔符);一個附加的"All GDI+ supported"(所有
GDI+支持)的過濾項被添入
舉例
#include "GdiplusFileOpenDialog.h"
// ...
bool CFoo::LoadImage(Image*& pImage)
{
bool bLoaded = false;
CGdiplusFileOpenDialog dlgFile;
if(IDOK == dlgFile.DoModal())
{
CString strPathName = dlgFile.GetPathName();
pImage = Image::FromFile(strPathName.AllocSysString());
Status status = pImage->GetLastStatus();
if(Ok == status)
{
bLoaded = true;
}
}
return bLoaded;
}
CGdiplusFileSaveAsDialog類
CGdiplusFileSaveAsDialog實現文件保存的通用型對話框。
覆寫CGdiplusFileDialog::FillCodecInfoArray并調用
Gdiplus::GetImageEncoders來填充關于可用編碼器的信息數組。
?文件格式的名稱(如:" BMP ")
?已用擴展名(如:"*. BMP、*. DIB、*. RLE ")
?在保存對話框中使用的缺省擴展名(如:" BMP ")
覆寫CGdiplusFileDialog::ConstructMFCStyleFilter構建"MFC 樣式"的過濾器
(使用一個''|''作為分隔符)
覆寫CFileDialog::OnInitDone 和 CFileDialog::OnTypeChange來設置缺省擴展
名并裝入缺省編碼器標識碼(m_clsid成員變量)
實現public方法GetCodecCLSID;codec(編碼器/譯碼器)CLSID進一步被傳遞到
Gdiplis::Image::Save函數
覆寫CFileDialog::OnFileNameOK以實現文件擴展名檢查:
?如果文件名沒有擴展名,使用缺省擴展名和CLSID
?如果文件名有一個擴展名并且可以被codec信息數組找到,擴展名和相應的
CLSID將用來代替缺省值
?如果文件名有一個擴展名同時不能被codec信息數組找到,它返回TRUE同時對話
框保持顯示以便用戶輸入另一個文件名
舉例
#include "GdiplusFileSaveAsDialog.h"
// ...
bool CFoo::SaveImage(Image* pImage)
{
bool bSaved = false;
CGdiplusFileSaveAsDialog dlgFile;
if(IDOK == dlgFile.DoModal())
{
CLSID clsid = dlgFile.GetCodecCLSID();
CString strPathName = dlgFile.GetPathName();
Status status = pImage->Save(strPathName.AllocSysString(),
&clsid);
if(Ok == status)
{
bSaved = true;
}
}
return bSaved;
}
Demo應用程序
Demo應用程序是一個建立在MDI框架上的簡單的圖像瀏覽器。它演示了如何使用
CGdiplusFileOpenDialog 和CGdiplusFileSaveAsDialog.
StdAfx.h 中的包含和聲明
typedef unsigned __int32 ULONG_PTR;
#include < afxtempl.h >
#include < gdiplus.h >
#pragma comment(lib, "gdiplus.lib")
using namespace Gdiplus;
注意
對于比VC++6.0更新的版本,或如果你已安裝了platform SDK更新,請移去
ULONG_PTR的定義。
(僅在VC++ 6.0下)確保gdiplus.lib 的位置應在
Tools/Option/Directories/Library文件夾下;抑或你可以在pragma comment指
示中提供其完全路徑和文件名稱。
初始化和發布GDI+
你必須在做如何GDI+調用前調用GdiplusStartup,同時在你結束使用GDI+時調用
GdiplusShutdown。
class CDemoApp : public CWinApp
{
// ...
// Attributes
protected:
ULONG_PTR m_gdiplusToken;
// ...
// Implementation
protected:
bool InitGdiplus();
void TermGdiplus();
// ...
};
// Called from CDemoApp::InitInstance
bool CDemoApp::InitGdiplus()
{
GdiplusStartupInput gdiplusStartupInput;
Status status = GdiplusStartup(&m_gdiplusToken,
&gdiplusStartupInput,
NULL);
return (Ok == status);
}
// Called from CDemoApp::ExitInstance
void CDemoApp::TermGdiplus()
{
GdiplusShutdown(m_gdiplusToken);
}
使用CGdiplusFileOpenDialog
去掉調用基類信息處理器的ID_FILE_OPEN命令的缺省映射并將該命令映射到在一
個CWinApp派生類中處理(譯注:即Demo程序中的CDemoApp類)。
void CDemoApp::OnFileOpen()
{
CGdiplusFileOpenDialog dlgFile;
if(IDOK == dlgFile.DoModal())
{
OpenDocumentFile(dlgFile.GetPathName());
}
}
覆寫CDocument::OnOpenDocument虛函數。
class CDemoDoc : public CDocument
{
// ...
// Attributes
protected:
Image* m_pImage;
// Operations
public:
Image* GetImage() {return m_pImage;}
// ...
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CDemoDoc)
public:
virtual BOOL OnOpenDocument(LPCTSTR pszPathName);
//}}AFX_VIRTUAL
// ...
};
BOOL CDemoDoc::OnOpenDocument(LPCTSTR pszPathName)
{
SafeDeleteImage();
m_pImage = Image::FromFile(CString(pszPathName).AllocSysString());
return (Ok == m_pImage->GetLastStatus());
}
使用CGdiplusFileSaveAsDialog
在CDocument派生類(譯注:即Demo程序中的CDemoDoc類)中映射
ID_FILE_SAVE_AS命令。在CGdiplusFileSaveAsDialog::DoModal返回后,調用
GetPathName和GetCodecCLSID以傳遞(路徑、文件名、Codec CLSID)到
Image::Save方法。
void CDemoDoc::OnFileSaveAs()
{
CGdiplusFileSaveAsDialog dlgFile;
if(IDOK == dlgFile.DoModal())
{
CLSID clsid = dlgFile.GetCodecCLSID();
CString strPathName = dlgFile.GetPathName();
Status status = m_pImage->Save(strPathName.AllocSysString(),
&clsid);
if(Ok != status)
{
TRACE2(_T("\nFailed to save image in ''%s'' file\n")
_T("GDI+ Error: %u"),
strPathName,
status);
}
}
}
繪圖
在CDemoView::OnDraw中,使用一個Gdiplus::Graphics對象來繪圖。
注意這只是一個例子并且設計得盡可能的簡單。
void CDemoView::OnDraw(CDC* pDC)
{
CDemoDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
Image* pImage = pDoc->GetImage();
if(NULL != pImage)
{
Graphics graphics(*pDC);
Status status = graphics.GetLastStatus();
if(Ok == status)
{
graphics.DrawImage(pImage, 0, 0,
pImage->GetWidth(), pImage->GetHeight());
}
}
}
結束提示:
gdiplus.dll已經包含在Windows XP 和 Windows Server 2003中
對于運行在Microsoft Windows NT 4.0-SP6/2000/98/Me之上應用程序的可再分
發,gdiplus.dll是必需的。
如果你再分發gdiplus.dll,推薦你將之放入應用程序的文件夾。
下載
Platform SDK Update:包含GDI+頭文件,gdiplus.lib, 和 gdiplus.dll(VC++?
6.0所需)
Platform SDK Redistributable: GDI+:可再分發gdiplus.dll,對于Windows?
NT 4.0-SP6/2000/98/Me
========
在MFC程序中顯示JPG/GIF圖像
文章概要:如果你是一個使用VB編程的程序員,要在程序中顯示JPG或者GIF圖像
簡直易如反掌,將圖像控件拖到Form中,分分鐘即可搞掂。但是C++程序員要顯
示同樣的圖形卻沒有那么輕松,那么是不是要自己編寫JPG解壓縮代碼呢?當然
不用那么復雜啦!本文將針對這個問題討論如何在MFC中顯示JPG或者GIF圖像。
如果你是一個使用VB編程的程序員,要在程序中顯示JPG或者GIF圖像簡直易如反
掌,將圖像控件拖到Form中,分分鐘即可搞掂。但是C++程序員要顯示同樣的圖
形卻沒有那么輕松,那么是不是要自己編寫JPG解壓縮代碼呢?當然不用那么復
雜啦!本文將針對這個問題討論如何在MFC中顯示JPG或者GIF圖像。
用VB寫圖像顯示程序之所以如此輕松,完全是利用了琳瑯滿目的圖像處理控件,
把你想要做的事情都一一搞掂。而C++程序員為了實現相同的功能必須忙乎半天
。其實,C/C++程序員也能使用那些VB程序員所用的(或者說幾乎一樣的)圖像
控件。VB用的圖像控件實際上都基于一個系統級COM類――IPicture。下面是有
關 IPicture 的方法描述:
方法 描述
get_Handle 返回圖像對象的Windows GDI句柄?
get_Hpal 返回圖像對象當前使用的調色板拷貝
get_Type 返回當前圖像對象的的圖像類型
get_Width 返回當前圖像對象的圖像寬度
get_Height 返回當前圖像對象的圖像高度
Render 在指定的位置、指定的設備上下文上繪制指定的圖像部分
set_Hpal 設置當前圖像的調色板
get_CurDC 返回當前選中這個圖像的設備上下文
SelectPicture 將一個位圖圖像選入給定的設備上下文,返回選中圖像的設備
上下文和圖像的GDI句柄
get_KeepOriginalForma 返回圖像對象KeepOriginalFormat 屬性的當前值
put_KeepOriginalFormat 設置圖像對象的KeepOriginalFormat 屬性
PictureChanged 通知圖像對象它的圖像資源改變了
SaveAsFile 將圖像數據存儲到流中,格式與存成文件格式相同
get_Attributes 返回圖像位屬性當前的設置
從上面這個表可以看出,IPicture操縱著圖像對象及其屬性。圖像對象提供對位
圖的抽象,而Windows負責BMP、JPG和GIF位圖的標準實現。程序員要做的只是實
例化IPicture,然后調用其Render函數。與通常使用接口的方式不同,這里實例
的創建我們不用CoCreateInstance函數,而是用一個專門的函數OleLoadPicture
。
1.
IStream* pstm = // 需要一個流(stream)
2.
IPicture* pIPicture;
3.
hr = OleLoadPicture(pstm, 0, FALSE, IID_IPicture, (void**)&pIPicture);
OleLoadPicture從流中加載圖像并創建一個可用來顯示圖像的新IPicture對象。
1.
rc = // 顯示圖像的矩形
2.
// 將rc 轉換為 HIMETRIC
3.
spIPicture->Render(pDC, rc);
?IPicture 負責處理所有瑣事,以便確定圖形之格式,如 Windows 位圖、JPEG
或者GIF文件――甚至是圖標和元文件(metafiles)。當然啦,所有這些的實現
細節是需要技巧的,為此我寫了一個Demo程序Myimgapp(如圖二)來示范這些
IPicture的使用方法。
?
圖一 Myimgapp的運行畫面?
Myimgapp是個典型的MFC文檔/視圖程序,在編寫這個程序之前,我首先對?
IPicture COM接口進行封裝,之所以要這么做,主要是考慮到并不是每一個程序
員都能熟練運用COM接口進行編程,另外將IPicture的主要功能封裝在C++類中可
以使我們的問題更容易解決,我封裝的這個C++類名字叫做CPicture。它的定義
和實現細節請參考本文提供的源代碼。?
我在這個類中將復雜而陌生的COM風格的參數映射成MFC程序員更為熟悉的類型。
例如,CPicture可以讓你直接從文件名加載一幅圖像,CFile或者CArchive,而
不用去處理流,CPicture::Render替你完成了IPicture中所有令人討厭的但又是
必須的HIMETRIC平滑轉換工作。CPicture甚至具備了一個Load函數,它可以從資
源數據中加載圖像,所以你只要用下面的代碼就可以顯示資源中的圖像:
1.
CPicture pic(ID_MYPIC); // 加載圖像
2.
CRect rc(0,0,0,0); ? ? ?// 使用缺省的rc
3.
pic.Render(pDC, rc); ? ?// 顯示圖像
CPicture::Render提供一個顯示圖片的矩形。IPicture 對圖像進行延伸處理。
如果傳遞一個空矩形,則CPicture用圖像本身的大小--不進行延伸處理。對于圖
像本身而言,CPicture查找"IMAGE"類型的資源,所以在資源文件中你必須要加
入下面的代碼:
1.
IDR_MYPIC IMAGE MOVEABLE PURE "res\\MyPic.jpg"
?CPicture是個很棒的傻瓜類,它具備一個 ATL 智能指針CComQIPtr指向
IPicture接口,通過調用OleLoadPicture來初始化不同的Load函數。CPicture提
供了常用的打包函數來調用底層的IPicture。CPicture只封裝了那些在Demo例子
程序中要用到的方法。如果你需要調用IPicture::get_Handle或其它一些很少用
到的IPicture方法,你可以自己嘗試編寫相應的打包代碼。 另外,在編寫完
CPicture之后,我發現了一個現成的MFC類――CPictureHolder,這個類的功能
幾乎與CPicture完全一樣,你可以在afxctl.h文件中找到它的定義。 前面說過
,Demo例子是個典型的MFC文檔/視圖應用程序,因此它肯定少不了與文檔和視圖
類相對應的CPictureDoc 和CPictureView:
CPictureDoc類沒有什么特別的處理代碼,它用CPicture對象存儲圖像:
1.
class CPictureDoc : public CDocument {
2.
protected:
3.
CPicture m_pict; // the picture
4.
};
并且CPictureDoc::Serialize 調用CPicture::Load 從MFC存檔的數據中讀取圖
像。
1.
void CPictureDoc::Serialize(CArchive& ar)
2.
{
3.
if (ar.IsLoading()) {
4.
m_pict.Load(ar);
5.
}
6.
}
為了使Myimgapp程序更實用,CPictureDoc::OnNewDocument從程序資源數據加載
了一幅圖像。為了顯示這幅圖像,CPictureView::OnDraw要調用
CPicture::Render。這樣程序一啟動便會顯示一幅默認的圖像。
1.
void CPictureView::OnDraw(CDC* pDC)
2.
{
3.
CPictureDoc* pDoc = GetDocument();
4.
CPicture* ppic = pDoc->GetPicture();
5.
CRect rc;
6.
GetImageRect(rc);
7.
ppic->Render(pDC,rc);
8.
}
GetImageRect是CPictureView類的一個成員函數,作用是根據當前Myimgapp的縮
放比率(可用25%、33%、50%、75%、100%或自適應方式)獲取圖像矩形。
GetImageRect調用CPicture::GetImageSize來獲得真正的圖像大小,然后根據比
率顯示。 CPictureView其余的部分完全和CScrollView的做法差不多,初始化視
圖并設置滾動大小,處理命令等等。唯一讓人操心的是IPicture::Render中
HIMETRIC的處理問題,因為標準的MFC應用程序都使用MM_TEXT映射模型。不用擔
心,CPicture::Render和CPicture::GetImageSize會將這一切轉換過來,所以你
不必為這些事情傷神。 CPictureView有一個消息處理器值得一提:它就是
OnEraseBkgnd,當要顯示的圖像比客戶區小的時候,這個函數必須繪制空白區域
,如圖二,OnEraseBkgnd創建一個與圖像大小相等的切邊(clip)矩形,然后將
客戶區填成黑色。之所以要創建切邊矩形,主要是避免當改變窗口大小時出現的
抖動――FillRect不繪制切邊矩形內的區域,此乃Windows圖形處理的常識。
?
圖二 OnEraseBkgnd 填充修剪的圖像?
IPicture/CPicture簡化了圖像的顯示。它甚至可以實現調色板的識別這樣復雜
的處理。你完全可以拋開老式DIB 圖像繪制方法,如加載調色板、BitBlts、
StretchBlts等等――這一切IPicture全都可以搞掂。如果你未曾用IPicture顯
示過圖像,那么現在試試吧。 CPictureView完成圖像瀏覽的任務看來不是什么
難事了。但是如果要把一幅圖像添加到一個對話框或者其它的什么窗口中怎么辦
呢?為此我創建了另外一個類――CPictureCtrl。
CPictureCtrl 使你可以在任何對話框或窗口中把圖像作為子窗口顯示。例如:
01.
class CAboutDialog : public CDialog {
02.
protected:
03.
CPictureCtrl m_wndPict;
04.
virtual BOOL OnInitDialog();
05.
};
06.
BOOL CAboutDialog::OnInitDialog()
07.
{
08.
m_wndPict.SubclassDlgItem(IDC_MYIMAGE,this);
09.
return CDialog::OnInitDialog();
10.
}
?假設你的對話框中有一個靜態控制,它的ID=IDC_IMAGE,并且有一幅IMAGE資源
的ID與之相同。則從CStaticLink派生出的CPictureCtrl還可以指定一個URL超鏈
接(或者創建一個ID與此控制或圖像的ID相同的串資源)。如果你指定了一個
URL,則在圖像上單擊鼠標將啟動默認瀏覽器訪問URL。真是酷呆了。CPicture控
制著CPicture對象并改寫WM_PAINT消息處理例程,調用CPicture::Render代替通
常的靜態控制處理例程。處理細節請參見代碼。打開Myimgapp程序的“關于”對
話框就知道了。
========
利用IJG JPEG Library壓縮圖像為jpg格式
文章概要:本文介紹了使用IJG JPEG庫將圖像轉換為JPG格式
前一段時間做了一個項目,項目中有一部分是關于圖像采集的,相關硬件有:高
速數字相機(我們采用Basler A312f),工控機,服務器。其中相機通過139
4視頻線連接到工控機的1394視頻卡上,工控機與服務器通過百兆網連接。
具體工作流程為:工控機控制相機采集圖像,幀率一般為40HZ左右,采集的
圖像為位圖數據,需要自己在程序中封裝為bmp格式,然后壓縮成jpg格式,壓縮
后的圖像一方面保存到本地硬盤,同時要傳輸到服務器上。
本文只介紹jpeg壓縮的相關內容,剛開始我貪圖省事,采用微軟 的GDI Plus提
供的功能,很是方便,先獲取jpg圖像的編碼,然后根據圖像的位圖數據創建一
個Bitmap類的對象,再保存圖像為jpg格式就行了。但是我對GDI+還是很信任,
總感覺不踏實(沒有理由的),我們的系統一旦安裝就要長期運行,我就是擔心
長期運行一段時間后GDI+會出問題,結果也證實了我的擔心,我們實際使用的1
0套系統中有一套,連續運行3-5天后,GDI+就會崩潰,于是我決心采用IJG?
JPEG Library。您可以到www.ijg.org網站下載libjpeg的源碼, IJG JPEG?
Library就是jpeg壓縮庫,是以源碼的形式提供給軟件開發人員的,當然在軟件
包里也有編譯好的庫文件,我們這里就只用到其中的libjpeg.lib,jconfig.h,
jmorecfg.h,jpeglib.h這幾個文件,下面我就介紹一下怎樣在自己的程序里嵌
入圖像壓縮功能。
一、建立編譯環境
所謂建立編譯環境,其實非常簡單,就是把上面提到的4個文件拷貝到你的項目
文件夾下,把libjpeg.lib添加到你的項目中,然后在你完成壓縮功能的那個文
件里加入#include "jpeglib.h",需要注意的是,libjpeg.lib是用c語言開發的
,如果要用在你的C++程序里,需要用到extern "C",如下:
1.
// TestLibjpeg.cpp : Defines the entry point for the console?
application.
2.
//
3.
?
4.
#include "stdafx.h"
5.
#include "memory.h"
6.
extern "C" {
7.
#include "jpeglib.h"
8.
}
二、壓縮步驟
1、申請并初始化jpeg壓縮對象,同時要指定錯誤處理器
1.
struct jpeg_compress_struct jcs;
2.
?
3.
// 聲明錯誤處理器,并賦值給jcs.err域
4.
struct jpeg_error_mgr jem;
5.
jcs.err = jpeg_std_error(&jem);
6.
?
7.
jpeg_create_compress(&jcs);
2、指定壓縮后的圖像所存放的目標文件,注意,目標文件應以二進制模式打開
1.
f=fopen("03.jpg","wb");
2.
if (f==NULL)
3.
{
4.
delete [] data;
5.
delete [] pDataConv;
6.
return 0;
7.
}
8.
jpeg_stdio_dest(&jcs, f);
3、設置壓縮參數,主要參數有圖像寬、高、色彩通道數(1:索引圖像,3:
其他),色彩空間(JCS_GRAYSCALE表示灰度圖,JCS_RGB表示彩色圖像),壓縮
質量等,如下:
1.
jcs.image_width = nWidth; ? ?// 為圖的寬和高,單位為像素
2.
jcs.image_height = nHeight;
3.
jcs.input_components = 1; ? // 在此為1,表示灰度圖, 如果是彩色位圖,則
為3
4.
jcs.in_color_space = JCS_GRAYSCALE; //JCS_GRAYSCALE表示灰度圖,JCS_RGB
表示彩色圖像
5.
?
6.
jpeg_set_defaults(&jcs);
7.
jpeg_set_quality (&jcs, 80, true);
需要注意的是,jpeg_set_defaults函數一定要等設置好圖像寬、高、色彩通道
數計色彩空間四個參數后才能調用,因為這個函數要用到這四個值,調用
jpeg_set_defaults函數后,jpeglib庫采用默認的設置對圖像進行壓縮,如果需
要改變設置,如壓縮質量,調用這個函數后,可以調用其它設置函數,如
jpeg_set_quality函數。其實圖像壓縮時有好多參數可以設置,但大部分我們都
用不著設置,只需調用jpeg_set_defaults函數值為默認值即可。
4、上面的工作準備完成后,就可以壓縮了,壓縮過程非常簡單,首先調用
jpeg_start_compress,然后可以對每一行進行壓縮,也可以對若干行進行壓縮
,甚至可以對整個的圖像進行一次壓縮,壓縮完成后,記得要調用
jpeg_finish_compress函數,如下:
01.
jpeg_start_compress(&jcs, TRUE);
02.
?
03.
JSAMPROW row_pointer[1]; ? // 一行位圖
04.
int row_stride; ? ? ?// 每一行的字節數
05.
?
06.
row_stride = jcs.image_width; ?// 如果不是索引圖,此處需要乘以3
07.
?
08.
// 對每一行進行壓縮
09.
while (jcs.next_scanline < jcs.image_height) {
10.
row_pointer[0] = & pDataConv[jcs.next_scanline * row_stride];
11.
jpeg_write_scanlines(&jcs, row_pointer, 1);
12.
}
13.
?
14.
jpeg_finish_compress(&jcs);
5、最后就是釋放壓縮工作過程中所申請的資源了,主要就是jpeg壓縮對象,由
于在本例中我是直接用的局部變量,所以只需調用jpeg_destroy_compress這個
函數即可,如下:
1.
jpeg_destroy_compress(&jcs);
三、解壓縮步驟
解壓縮步驟與壓縮步驟非常相似,只是解壓縮對象為jpeg_decompress_struct類
型,步驟如下:
1、聲明并初始化解壓縮對象,同時制定錯誤信息管理器
1.
struct jpeg_decompress_struct cinfo;
2.
struct jpeg_error_mgr jerr;
3.
?
4.
cinfo.err = jpeg_std_error(&jerr);
5.
jpeg_create_decompress(&cinfo);
2、打開jpg圖像文件,并指定為解壓縮對象的源文件
1.
FILE *f = fopen(strSourceFileName,"rb");
2.
if (f==NULL)
3.
{
4.
printf("Open file error!\n");
5.
return;
6.
}
7.
//
8.
jpeg_stdio_src(&cinfo, f);
3、讀取圖像信息
1.
jpeg_read_header(&cinfo, TRUE);
4、根據圖像信息申請一個圖像緩沖區
1.
data = new BYTE?
cinfo.image_width*cinfo.image_height*cinfo.num_components];
5、開始解壓縮
01.
jpeg_start_decompress(&cinfo);
02.
?
03.
JSAMPROW row_pointer[1];
04.
while (cinfo.output_scanline < cinfo.output_height)
05.
{
06.
row_pointer[0] = &data[(cinfo.output_height - cinfo.output_scanline-
1)*cinfo.image_width*cinfo.num_components];
07.
jpeg_read_scanlines(&cinfo,row_pointer ,
08.
1);
09.
}
10.
jpeg_finish_decompress(&cinfo);
6、釋放資源
1.
jpeg_destroy_decompress(&cinfo);
2.
?
3.
fclose(f);
好了,利用IJG JPEG Library進行圖像壓縮就介紹到這里,希望對大家有所幫助
,實例代碼已經實現了圖像的壓縮和解壓縮的全部功能,命令格式
為:“TestLibjpeg.exe j|j24|b 源文件名 目標文件名”,其中,j選項將源文
件壓縮為jpg格式,不改變色彩模式,j24選項將源文件壓縮為24為jpg格式,b選
項將源文件解壓縮為bmp格式,該實例并沒有提供文件有效性的驗證,如果要引
入自己的代碼,請自己實現文件有效性的驗證。
========
通過VB結構數組輸入數據VC編寫DLL實現圖形文件
文章概要:太多的例子講如何如何實現VC編寫動態鏈接庫,VB中聲明后使用,但沒
有一個好的文章來深入探討這個問題,本文負責解決此類問題。
前言
太多的例子講如何如何實現VC編寫動態鏈接庫,VB中聲明后使用,但沒有一個好的
文章來深入探討這個問題,本文負責解決此類問題。
1.一般情況
VB中定義為:
1.
Private Declare Function FuncFoo Lib "MyStDll.DLL" _
2.
(ByVal lParam1 As Long, ByVal lParam2 As Long) As Long
VC中定義為:
1.
UINT WINAPI FuncFoo(UINT lParam1, UINT lParam2);
不用說大家就知道兩個long參數,按值傳遞的
2.實現類型數組:
VB中定義為:
1.
Private Declare Function FuncFoo Lib "MyStDll.DLL" _
2.
(lParam1 As Long, ByVal lParam2 As Long) As Long
VC中定義為:
1.
UINT WINAPI FuncFoo(UINT lParam1[DATASIZE], UINT lParam2);
其中DATASIZE為定義常數ByRef 按地址傳參數,當然VB缺省參數形式ByRef,將數
組的第一個數據傳入,就是這個類型數組的地址了
用法如下:
1.
...
2.
Dim oData(1 to 3) as Long
3.
oData(1) = 100
4.
oData(2) = 200
5.
oData(3) = 300
6.
Call FuncFoo(oData(0),3)
7.
...
3.實現結構數組:
如果此時用上述方法
在VB中來這樣寫:
1.
Private Type LPDATA
2.
Row as Long
3.
Col as Long
4.
Tips as String
5.
Data as double
6.
End Type
7.
Private Declare Function FuncFoo Lib "MyStDll.DLL" _
8.
(lParam1 As LPDATA, ByVal lParam2 As Long) As Long
在VC中這樣寫:
1.
typedef struct tagData {
2.
UINT Row;
3.
UINT Col;
4.
BSTR Tips; //注意一般關于字符串最好用 BSTR ,后面解釋為什么
5.
double Data;
6.
} * LPDATA;
7.
UINT WINAPI FuncFoo(LPDATA lParam1[DATASIZE] ,UINT lParam2);或
8.
UINT WINAPI FuncFoo(LPDATA *lParam1 ,UINT lParam2);
這樣的結果大家不妨試一試,數據亂的毫無規律,我也很不解,搞不懂,網上
SOS,HELP me,目前最流行的方式,我也用上了,國內外知名的,被遺忘的角落,等等
,大家沒人理我,可能看到了不解,個中高手過著深入簡出的生活,沒有回答,沒人
解答,我從MSDN終于搞到一個東西他就是SAFEARRARY
01.
typedef struct FARSTRUCT tagSAFEARRAY {
02.
unsigned short cDims;
03.
unsigned short fFeatures;
04.
unsigned short cbElements;
05.
unsigned short cLocks;
06.
unsigned long handle;
07.
void HUGEP *pvData ;
08.
SAFEARRAYBOUND rgsabound[1];
09.
} SAFEARRAY;
下次我再單獨寫篇稿子討論這個東西,解決問題先. 應該這么做
在VB中來這樣寫:
1.
Private Type LPDATA
2.
Row as Long
3.
Col as Long
4.
Tips as String
5.
Data as double
6.
End Type
7.
Private Declare Function FuncFoo Lib "MyStDll.DLL" _
8.
(lParam1() As LPDATA, ByVal lParam2 As Long) As Long
用法如下:
1.
...
2.
Dim oData(1 to 3) as Long
3.
oData(1) = 100
4.
oData(2) = 200
5.
oData(3) = 300
6.
Call FuncFoo(oData(),3)
7.
...
在VC中這樣寫:
1.
typedef struct tagData {
2.
UINT Row;
3.
UINT Col;
4.
BSTR Tips; //注意一般關于字符串最好用 BSTR ,后面解釋為什么
5.
double Data;
6.
} * LPDATA;
7.
UINT WINAPI FuncFoo(LPSAFEARRAY FAR * Param1,UINT lParam2);
在VC中訪問VB傳入的結構數據:
1.
LPDATA lparDataSet;
2.
lparDataSet = (LPDATA)((*Param1)->pvData);
3.
for (UINT u=0;u<((*Param1)->rgsabound->cElements);u++,lparDataSet++)
4.
{
5.
UINT aa = lparDataSet->Row;
6.
CString bb = lparDataSet->Tips;
7.
double cc = lparDataSet->Data;
8.
}
注意:為什么用BSTR不用什么LPCTSTR xxx,TCHAR xxx[mmm],char xxx[mmm],我舉
個例子大家試一試就知道了
1. VB送入字符 "個大12"
2. 正常VC顯示數據為 B8 F6 B4 F3 31 32
3. VC結構傳入顯示為 2A 4E 27 59 31 00 32 00 (unicode?)
第一部分寫到這里吧,剩下的東西還是等各位朋友自己慢慢去摸索,倉促難免有
疏漏之處,請各位諒解。
作者信息:
阿鬼 [ http://GhostStudio.yeah.net ]
本文寫于:2001/10/26 15:40
分享到:新浪微博 騰訊微博 更多 0 收藏
========
用CabLib創建DXF(繪圖交換格式)文件
文章概要:本文詳細介紹了DXF文件的格式以及用CabLib生成圖形并存儲為DXF文
件的方法,并提供了CabLib的源代碼以及測試代碼。
介紹
什么是DXF
繪圖交換格式(DXF)文件允許在AutoCAD和其它程序進行圖形交換。DXF文件即可
以是ASCII格式也可以是二進制格式。 因為ASCII格式的DXF文件比二進制格式更
加通用,所以CadLib使用ASCII的DXF格式。
什么是CadLib
CadLib不是計算機輔助設計(CAD)程序。它是創建用于CAD程序DXF文件的工具。
它由兩部分組成,一部分是用于創建DXF文件的動態鏈接庫,另一部分是編程接
口,該類封裝了cadio.dll中的函數,可以在Microsoft Visual C++項目中使用
。另外,cadio.dll 也可以用于其它Win32編程中。
為什么使用CadLib
一些程序需要輸出可以被AutoCad等程序使用的圖形文件,例如,在一個"發動機
設計程序"中,程序需要輸出圖形,而最常用的交換數據的圖形格式便是DXF。
?
DXF文件結構
DXF文件格式是圖形文件中所有信息的標簽數據描述。標簽數據指的是文件中的
被稱為群碼的整型數據前的每個數據項。 群碼的值指示了下面數據的數據類型
以及數據單元的含義。事實上圖形文件中所有用戶特殊信息都可以描述為DXF格
式。(參考AutoCad的DXF參考說明)
DXF文件由許多區域組成,每個區域里有許多圖形數據,CadLib可以使用如下區
域:
1. 頭部 HEADER
2. 表格 TABLES
3. 區塊 BLOCKS
4. 實體 ENTITIES
CadLib中的DXF文件結構參考AutoCad中的DXF格式說明,具體可以在下面網址找
到參考:
http://www.autodesk.com/techpubs/autocad/acad2000/dxf/dxf_format.htm
http://www.martinreddy.net/gfx/3d/DXF12.spec
類
這里的類是CadIO.dll和主程序之間的接口。"Test"演示了如何用CadLib中的
CDxfFileWrite和CDrawing類創建DXF文件。
CDxfFileWrite類
CDxfFileWrite封裝了直接創建DXF文件的所有命令。使用方法如下:
1. 創建DXF文件
1.
CDxfFileWrite dxffile;
2.
dxffile.Create( "d:\\test.dxf" );
2. HEADER區域的開始與結束。這里是為了兼容CAD程序。其它的不需要HEADER區
域。
1.
// Header Section ------------------------------------------
2.
dxffile.BeginSection(SEC_HEADER);
3.
dxffile.EndSection();
4.
// close HEADER section ------------------------------------
3. 開始表格區域并放置LAYER, LTYPE, STYLE, DIMSTYLE等你所需的表格類型,
然后結束該區域。
01.
// Tables Section ------------------------------------------
02.
dxffile.BeginSection(SEC_TABLES);
03.
?
04.
// LTYPE table type -------------------------
05.
dxffile.BeginTableType(TAB_LTYPE);
06.
?
07.
DXFLTYPE ltype;
08.
double elem[4];
09.
?
10.
// Continuous
11.
ZeroMemory(<ype, sizeof(ltype));
12.
ltype.Name = "Continuous";
13.
ltype.DescriptiveText = "Solid line";
14.
dxffile.AddLinetype(<ype);
15.
?
16.
// DASHDOT2
17.
ZeroMemory(<ype, sizeof(ltype));
18.
ltype.Name = "DASHDOT2";
19.
ltype.DescriptiveText = "Dash dot (.5x)?
_._._._._._._._._._._._._._._.";
20.
ltype.ElementsNumber = 4;
21.
ltype.TotalPatternLength = 0.5;
22.
ltype.Elements = elem;
23.
elem[0] = 0.25;
24.
elem[1] = -0.125;
25.
elem[2] = 0.0;
26.
elem[3] = -0.125;
27.
dxffile.AddLinetype(<ype);
28.
?
29.
dxffile.EndTableType();
30.
// close LTYPE table type -------------------
31.
?
32.
// LAYER table type -------------------------
33.
result &= dxffile.BeginTableType(TAB_LAYER);
34.
result &= dxffile.AddLayer("Layer1", 1, "Continuous");
35.
result &= dxffile.AddLayer("Layer2", 2, "Continuous");
36.
result &= dxffile.AddLayer("Layer3", 3, "Continuous");
37.
result &= dxffile.AddLayer("Layer4", 4, "Continuous");
38.
result &= dxffile.EndTableType();
39.
// close LAYER table type -------------------
40.
?
41.
// STYLE table type -------------------------
42.
dxffile.BeginTableType(TAB_STYLE);
43.
?
44.
DXFSTYLE tstyle;
45.
ZeroMemory(&tstyle, sizeof(tstyle));
46.
tstyle.Name = "Style1";
47.
tstyle.PrimaryFontFilename = "TIMES.TTF";
48.
tstyle.Height = 0.3;
49.
tstyle.WidthFactor = 1;
50.
dxffile.AddTextStyle(&tstyle);
51.
?
52.
dxffile.EndTableType();
53.
// close STYLE table type -------------------
54.
?
55.
// DIMSTYLE table type ----------------------
56.
dxffile.BeginTableType(TAB_DIMSTYLE);
57.
?
58.
DXFDIMSTYLE dimstyle;
59.
?
60.
// DIM1
61.
ZeroMemory(&dimstyle, sizeof(dimstyle));
62.
dimstyle.Name = "DIM1"; // DimStyle Name
63.
dimstyle.DIMCLRD = 2; // Dimension line & Arrow heads color
64.
dimstyle.DIMDLE = 0.0000; // Dimension line size after Extensionline
65.
dimstyle.DIMCLRE = 2; // Extension line color
66.
dimstyle.DIMEXE = 0.1800; // Extension line size after Dimline
67.
dimstyle.DIMEXO = 0.0625; // Offset from origin
68.
dimstyle.DIMBLK1 = "ClosedFilled";// 1st Arrow head
69.
dimstyle.DIMBLK2 = "ClosedFilled";// 2nd Arrow head
70.
dimstyle.DIMASZ = 0.1800; // Arrow size
71.
dimstyle.DIMTXSTY = "Style1"; // Text style
72.
dimstyle.DIMCLRT = 3; // Text color
73.
dimstyle.DIMTXT = 0.1800; // Text height
74.
dimstyle.DIMTAD = 1; // Vertical Text Placement
75.
dimstyle.DIMGAP = 0.0900; // Offset from dimension line
76.
dxffile.AddDimStyle(&dimstyle);
77.
?
78.
dxffile.EndTableType();
79.
// close DIMSTYLE table type ----------------
80.
?
81.
dxffile.EndSection();
82.
// close TABLES section ------------------------------------
4. 開始實體區域并放置LINE, CIRCLE, SOLID, TEXT, ARC, POINT, DIMLINEAR
等數據,然后結束該區域。
01.
// Entities Section ------------------------------------------
02.
dxffile.BeginSection(SEC_ENTITIES);
03.
?
04.
// set current layer to Layer2
05.
dxffile.SetCurrentLayer("Layer2");
06.
// draw a line
07.
dxffile.Line(1.2, 3.3, 7.5, 7.7);
08.
// draw a circle
09.
dxffile.Circle(7.8, 4.3, 1.75);
10.
// set current layer to Layer4
11.
dxffile.SetCurrentLayer("Layer4");
12.
?
13.
// draw a solid
14.
REALPOINT points[4];
15.
points[0].x = 10.4; points[0].y = 7.2;
16.
points[1].x = 13.6; points[1].y = 7.4;
17.
points[2].x = 13.1; points[2].y = 4.9;
18.
points[3].x = 10.9; points[3].y = 5.9;
19.
Solid(4, points);
20.
?
21.
// set current textstyle to Style1
22.
dxffile.SetCurrentTextStyle("Style1");
23.
// draw text
24.
dxffile.Text("Sample Text", 5.9, 6.7, 0.3, 35);
25.
// draw a dimension line
26.
dxffile.SetCurrentDimStyle("DIM1");
27.
dxffile.DimLinear(6.05, 3, 9.55, 3, 9.55, 2, 0, "3.50");
28.
?
29.
dxffile.EndSection();
30.
// close ENTITIES section ----------------------------------
5. 關閉DXF文件
dxffile.Close();
CDrawing 類
CDrawing封裝了在內存中創建圖形并保存到DXF文件中的功能。使用方法如下:
1. 創建內存繪圖
CDrawing drw;
drw.Create();
2. 在內存中創建LAYER, LTYPE, STYLE, DIMSTYLE等所需要的表格類型
01.
// Tables Section ------------------------------------------
02.
// LTYPE table type -------------------------
03.
LTYPE ltype;
04.
OBJHANDLE objhandle1;
05.
?
06.
// Continuous
07.
ZeroMemory( 3. 生成實體數據(LINE, CIRCLE, SOLID, TEXT, ARC, POINT,?
DIMLINEAR, POLYLINE)
08.
// Entities Section ------------------------------------------
09.
// set current layer to Layer2
10.
drw.SetLayer("Layer2");
11.
// draw a line
12.
drw.Line(1.2, 3.3, 7.5, 7.7);
13.
// draw a circle
14.
drw.Circle(7.8, 4.3, 1.75);
15.
// set current layer to Layer1
16.
drw.SetLayer("Layer1");
17.
?
18.
// draw a solid
19.
REALPOINT points[4];
20.
points[0].x = 10.4; points[0].y = 7.2;
21.
points[1].x = 13.6; points[1].y = 7.4;
22.
points[2].x = 13.1; points[2].y = 4.9;
23.
points[3].x = 10.9; points[3].y = 5.9;
24.
drw.Solid(points[0], points[1], points[2], points[3]);
25.
?
26.
// set current textstyle to Style1
27.
drw.SetTextStyle("Style1");
28.
// draw text
29.
drw.Text("Sample Text", 5.9, 6.7, 0.3, 35);
30.
// draw a dimension line
31.
drw.SetDimStyle("DIM1");
32.
drw.DimLinear(6.05, 3, 9.55, 3, 9.55, 2, 0, "3.50");
4. 將數據保存到DXF文件中
1.
drw.SaveDXFFile(DxfFileName);
5. 刪除CDrawing對象并釋放內存
從DXF文件中加載數據
1. 創建內存繪圖?
1.
CDrawing drw;
2.
drw.Create( );
2. 使用LoadDXFFile加載DXF文件到內存
1.
drw.LoadDXFFile("Sample.dxf");
結論
這些代碼對于需要在程序中創建DXF文件的程序員來說是很有用的,CadLib雖然
不是創建DXF文件最好的商業軟件,但它是開源的,可以自由修改代碼。
========
(GDI+)Image類的序列化
文章概要:本文介紹如何采用GDI+ 通過IMAGE類的序列化實現對圖形文件的讀取、顯示。
利用GDI+圖形設備接口提供的Image類我們可以很方便地顯示JPEG、GIF等文件格式的圖片,但美中不足的是Image類未提供序列化數據的功能,如果要將從JPEG、GIF等格式的文件中讀取的圖片數據保存到我們自己開發的應用程序文檔中,并能從文檔中讀取已經保存的圖片數據并正確的顯示出來,就必須實現Image類數據的序列化。 假如在你的文檔類中有個指向Image類的成員指針變量m_pImage用于顯示圖片,那么在文檔類的序列化函數Serialize(CArchive& ar)中加入以下的代碼就能實現m_pImage所指向的圖片數據的序列化:
01.
if (ar.IsStoring())
02.
{
03.
HGLOBAL m_hMem = GlobalAlloc(GMEM_MOVEABLE, 0);
04.
IStream *pstm=NULL;
05.
CreateStreamOnHGlobal(m_hMem, TRUE, &pstm);
06.
CLSID clsid;
07.
USES_CONVERSION;
08.
GetCodecClsid(A2W("image/bmp"), &clsid);
09.
m_pImage->Save(pstm,&clsid,NULL);
10.
if (pstm==NULL)
11.
return;
12.
LARGE_INTEGER liBeggining = { 0 };
13.
pstm->Seek(liBeggining, STREAM_SEEK_SET, NULL);
14.
DWORD wTemp=GlobalSize(m_hMem);
15.
LPBYTE lpData = (LPBYTE)GlobalLock(m_hMem);
16.
ar << wTemp;
17.
ar.Write(lpData,wTemp);
18.
pstm->Release();
19.
GlobalUnlock(m_hMem);
20.
}
21.
else
22.
{
23.
DWORD wTemp;
24.
ar >> wTemp;
25.
HGLOBAL m_hMem = GlobalAlloc(GMEM_FIXED, wTemp);
26.
if (m_hMem == NULL)
27.
return;
28.
IStream *pstm=NULL;
29.
CreateStreamOnHGlobal(m_hMem,FALSE,&pstm);
30.
if (pstm==NULL)
31.
return;
32.
BYTE* pmem = (BYTE*)GlobalLock(m_hMem);
33.
ar.Read(pmem,wTemp);
34.
if (m_pImage) {
35.
delete m_pImage;
36.
m_pImage = NULL;
37.
}
38.
using namespace Gdiplus;
39.
m_pImage = Image::FromStream(pstm, FALSE);
40.
pstm->Release();
41.
GlobalUnlock(m_hMem);
42.
//注意此處不能加GlobalFree(m_hMem);否則圖片顯示不出來。
其中函數GetCodecClsid的實現代碼如下:
01.
int GetCodecClsid(const WCHAR* format, CLSID* pClsid)
02.
{
03.
UINT ?num = 0; ? ? ? ? ?// number of image encoders
04.
UINT ?size = 0; ? ? ? ? // size of the image encoder array in bytes
05.
using namespace Gdiplus;
06.
ImageCodecInfo* pImageCodecInfo = NULL;
07.
GetImageEncodersSize(&num, &size);
08.
if(size == 0)
09.
return -1; ?// Failure
10.
pImageCodecInfo = (ImageCodecInfo*)(malloc(size));
11.
if(pImageCodecInfo == NULL)
12.
return -1; ?// Failure
13.
GetImageEncoders(num, size, pImageCodecInfo);
14.
for(UINT j = 0; j < num; ++j)
15.
{
16.
if( wcscmp(pImageCodecInfo[j].MimeType, format) == 0 )
17.
{
18.
*pClsid = pImageCodecInfo[j].Clsid;
19.
return j; ?// Success
20.
} ??
21.
} // for
22.
return -1; ?// Failure
23.
} // GetCodecClsid
形參format用以說明圖片數據的保存格式,可以取以下一些值:"image/bmp"(位圖格式),"image/jpeg"(JPEG格式),"image/gif"(GIF格式)等。
========
總結
以上是生活随笔為你收集整理的VC++图像存取总结的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: VC访问数据库学习总结
- 下一篇: 图解VC++6.0和ACE 5.4 开发