Friday, September 29, 2006

VFW: 取得視訊裝置驅動程式的資訊

任何一個電腦週邊硬體裝置安裝時, 作業系統必須要能與硬體裝置溝通, 我們把溝通媒介稱為驅動程式 ( device driver )。電腦與周邊裝置的溝通必需透過特定介面傳送資料, 傳送的資料也必須符合特定格式, 驅動程式可以認得傳送的資料為何, 就可以驅動硬體裝置執行電腦所派達的命令。

我們可以透過 capGetDriverDescription 這個函數, 讓應用程式知道你所使用的視訊裝置驅動程式相關資訊。如果你在 vfw.h 中搜尋, 你可以在 line 3618 找到底下這段定義與函數的宣告。

BOOL VFWAPI capGetDriverDescriptionA (UINT wDriverIndex,
LPSTR lpszName, int cbName,
LPSTR lpszVer, int cbVer);

BOOL VFWAPI capGetDriverDescriptionW (UINT wDriverIndex,
LPWSTR lpszName, int cbName,
LPWSTR lpszVer, int cbVer);

#ifdef UNICODE
#define capCreateCaptureWindow capCreateCaptureWindowW
#define capGetDriverDescription capGetDriverDescriptionW
#else
#define capCreateCaptureWindow capCreateCaptureWindowA
#define capGetDriverDescription capGetDriverDescriptionA
#endif
/* 說明:
1. 有關 #ifdef 的 C 前置處理的部份, 請參考 http://nknucc.nknu.edu.tw/~jwu/c/cpgch8.htm
2. capGetDriverDescriptionA 函數的傳回值為 BOOL ( 布林值, true or false ) , 傳入值一共有 5 個分別如下:
UINT wDriverIndex, 指定要取得的視訊裝置編號。( 你要先告訴人家要取得哪一個視訊裝置的相關資訊! )
LPSTR lpszName, 取得驅動程式的名稱後, 要儲存到哪一個字串給你知道呢?
( 注意: 這邊傳入的是這個字串的指標! )
int cbName, 指定存放驅動程式名稱的字串的大小。
LPSTR lpszVer, 取得驅動程式的版本後, 存放在這個字串中。
int cbVer, 指定存放驅動程式版本的字串的大小。
*/

範例程式:
long dwDriverIndex;
char szDeviceName[80]; // Driver Name
char szDeviceVersion[80]; // Driver Version

dwDriverIndex = 0;
if (capGetDriverDescription(dwDriverIndex, szDeviceName, sizeof(szDeviceName),
szDeviceVersion, sizeof(szDeviceVersion)))
{
lblCapDriverName->Caption = szDeviceName;
lblCapDriverVer->Caption = szDeviceVersion;
}

Thursday, September 28, 2006

VFW.H

Video For Windows ( VFW ) 是 Microsoft 於 1992 年所推出, 針對多媒體視訊的應用程式開發介面 ( Application Programming Interface , API )。只要本身有支援 VFW 的硬體裝置, 都可以透過 VFW SDK ( Software Development Kit ) 來控制, 並開發出有關音訊、視訊的多媒體處理軟體。

在 BCB 的目錄( C:\Program Files\Borland\CBuilder6\ ) 中, 你可以在 Include 子目錄裏找到 vfw.h 這個 header file, 當我們在 BCB 中要使用 VFW SDK 所提供的函數時, 就要將下面一行指令加入到程式的最前面。

#include <vfw.h>
 

Tuesday, September 26, 2006

Objects

An object is a specific region of memory that can hold a fixed or variable value (or set of values). (This use of the word object is different from the more general term used in object-oriented languages.) Each value has an associated name and type (also known as a data type). The name is used to access the object. This name can be a simple identifier, or it can be a complex expression that uniquely references the object. The type is used
  • to determine the correct memory allocation required initially.
  • to interpret the bit patterns found in the object during subsequent accesses.
  • in many type-checking situations, to ensure that illegal assignments are trapped.
C++Builder supports many standard (predefined) and user-defined data types, including signed and unsigned integers in various sizes, floating-point numbers in various precisions, structures, unions, arrays, and classes. In addition, pointers to most of these objects can be established and manipulated in memory.

The C++Builder standard libraries and your own program and header files must provide unambiguous identifiers (or expressions derived from them) and types so that C++Builder can consistently access, interpret, and (possibly) change the bit patterns in memory corresponding to each active object in your program.

Objects and declarations

Declarations establish the necessary mapping between identifiers and objects. Each declaration associates an identifier with a data type. Most declarations, known as defining declarations, also establish the creation (where and when) of the object; that is, the allocation of physical memory and its possible initialization. Other declarations, known as referencing declarations, simply make their identifiers and types known to the compiler. There can be many referencing declarations for the same identifier, especially in a multifile program, but only one defining declaration for that identifier is allowed.

Generally speaking, an identifier cannot be legally used in a program before its declaration point in the source code. Legal exceptions to this rule (known as forward references) are labels, calls to undeclared functions, and class, struct, or union tags.

Monday, September 25, 2006

TPicture

TPicture contains a bitmap, icon, metafile graphic, or user-defined graphic.

Hierarchy
TObject - TPersistent - TInterfacedPersistent - TPicture

Unit
Graphics

Description
TPicture is a TGraphic container, used to hold a graphic, the type of which is specified in the Graphic property. It is used in place of a TGraphic if the graphic can be of any TGraphic class. LoadFromFile and SaveToFile are polymorphic. For example, if the TPicture is holding an Icon, it is valid to LoadFromFile a bitmap file, where the class TIcon can only read .ICO files.

If the TPicture contains a bitmap graphic, the Bitmap property specifies the graphic. If the TPicture contains an icon graphic, the Icon property specifies the graphic. If the TPicture contains a metafile graphic, the Metafile property specifies the graphic.

The properties of TPicture indicate the type of graphic that the picture object contains, and its size. The methods of TPicture are used to load, save, and manipulate graphics.

To load or save a picture to the Clipboard, use the Assign method of a TClipboard object.

To draw a picture on a canvas, call the Draw or StretchDraw methods of a TCanvas object, passing the Graphic property of a TPicture as a parameter.

TImage

TImage displays a graphical image.
Hierarchy
TObject - TPersistent - TComponent - TControl - TGraphicControl - TImage

Unit
ExtCtrls

Description
Use TImage to display a graphical image on a form. Use the TPicture object in the Picture property to specify the actual bitmap, icon, metafile, or other graphic object displayed by TImage. Properties and methods of TPicture can be used for such things as loading an image from file, clearing the image in the TImage, and assigning an image for another control. TImage introduces several properties to determine how the image is displayed within the boundaries of the TImage object.

To add an image to a form or data module so that it is available for display by other controls, such as action lists and bitmap buttons, use a TImageList control instead.
如果要在 form 中顯示一張影像, 就必須要用到 Image 元件, 可以從 TImage 類別的 Help 資料著手, 了解 BCB 對於顯示影像是如何運作的。在 Image 元件中, 有一個屬性 ( property ) 稱為 Picture, 其型態原型為 TPicture, 是用來儲存影像資料的地方。

Component Palette


BCB 的核心除了以 C++ 程式語言為基礎之外, 最重要的就是 Visual Component Library 了。BCB 把在視窗應用程式 ( window application ) 中常用的一些功能, 包裝成一個個的元件 ( component ), 這些元件通通被放到上圖的 Component Palette 中, 由於元件太多了, 因此 BCB 用分頁選單的方式, 將性質相近的元件放到同一個標籤頁中, 方便我們使用。

你可以比較出畫家用的調色盤 ( palette ) 和 BCB 中的 component palette 之間的異同嗎?

Sunday, September 24, 2006

Visual Component Library (VCL)

視覺化元件程式庫( Visual Component Library, VCL ) 是 Borland 所發展出來的, 包含 Objects, Components, Routines, Types, Constants and Variables 等五大部分。底下的說明是從 Borland C++ Builder Help 所寫的說明文字。
Objects
An object consists of methods, and in many cases, properties, and events. Properties represent the data contained in the object. Methods are the actions the object can perform. Events are conditions the object can react to. All objects descend from the ancestor object TObject.

Components
Components are visual objects that you can manipulate at design time. All components descend from TComponent.

Routines
Global routines are the procedures and functions from the runtime library and from the VCL. These routines are not part of a class, but can be called either directly or from within class methods.

Types
The types described in the Help are used as return types and parameter types for object methods, properties and events, and for global routines. In many cases, types are documented in the entry for the method, property, event or global routine in which they are used.

Constants and Variables
The constants and variables defined in the Help are declared in the runtime library and in the VCL. Some of these are instantiations of objects. Examples are the Application and Screen variables. Others represent routines that provide the underlying implementation of other methods or global routines. Examples include the AnsiResemblesProc and RegisterComponentsProc variables. Still other variables and constants represent information that can vary with the system or platform, such as the DateSeparator variable and PathDelim constant.
Borland C++ Builder 是 Borland 針對 C++ 程式語言所開發的快速應用程式開發工具 ( Rapid Application Development, RAD ), Borland 為 C++ 加入了許多的視覺化元件, 配合整合開發環境 ( Integrated Development Environment, IDE ), 推出了 Borland C++ Builder 這個產品, 加速了一個視窗應用程式的開發。

Wednesday, September 13, 2006

動態宣告二維陣列

寫程式時, 『變數宣告』指的是請作業系統分配 (allocate) 一塊大小合適的記憶體, 讓我們作為儲存資料之用。因此, 我們必須告訴作業系統, 我們要儲存的資料是什麼型態, 然後, 根據程式設計師所提供的變數型態, 作業系統就會知道該分配多大的記憶體給我們使用。因此, 變數宣告通常會寫在程式的最前面, 希望程式一開始執行時, 就把需要用到的記憶體通通分配好。

標題中『動態宣告』指的是當程式設計師在寫程式時, 並無法確實知道程式在執行時需要用的多大的記憶體, 必須等到程式真正執行時(run time), 才會知道確實的大小。為了解決這樣的問題, 就必須允許程式設計師在執行程式時, 才臨時去宣告, 要求分配記憶體, 這就是『動態』兩個字的意義由來。

用二維陣列來儲存數位影像是非常直覺的想法, 不過, 需要用動態宣告方式的原因則是因為我們不知道要事先宣告一個多大的二維陣列才夠儲存你所開啟的影像。這邊就是要介紹 BCB 中, 要動態宣告一個二維陣列的作法。

#include <iostream.h>
// 注意: 必須加入這一行到程式最前面, 否則我們後面用到的 std::bad_alloc 會沒有定義

unsigned char **ucMatrix;
/* 說明:
1. ucMatrix 就是我們要宣告的二維陣列的名稱, 為了讓我們在寫程式時, 一看到這個名稱就知道其資料型態為何, 我們在名稱之前加入了小寫的 uc, 代表 unsigned char 的縮寫,
2. 這邊用 unsigned char 當例子的原因是影像的色彩值範圍為 0 ~ 255, 剛好就是 unsigned char 可以表示的數值範圍。
3. 名稱之前, 我們放了兩個 star 符號 ( ** ), 就是要告訴 BCB 的編譯器, 這個名稱本身是一個指到二維陣列的名稱。
結束說明 */

int iImageHeight=0, iImageWidth=0;

// 說明: 這兩個變數是用來儲存影像 ( image ) 的高 ( height ) 與寬 ( width ) 的, 至於變數名稱最前面的小寫 i, 也是用來指出其資料型態為 int

 try
  {
  ucMatrix = new unsigned char *[iImageHeight];
  for (j=0;j<iImageHeight;j++)
   ucMatrix[j] = new unsigned char [iImageWidth];
  }
 catch (std::bad_alloc)
  {
  ShowMessage("Could not allocate memory...Bye");
  exit(-1);
  }
 
/* 說明:
1. 如果有一段程式 ( 用大括號 {}, 括起來) 有可能發生一些特殊例外的情況, 以上面的例子來說, 要求系統給予一塊記憶體, 在一般情況下, 這段程式可以順利要到記憶體繼續執行; 可是, 當系統已經沒有多餘的記憶體分配給你的時候, 程式該怎麼辦呢? 這種情況就是可能發生的例外情況。在 C++ (BCB) 中, 你可以將這段程式碼的前面加上 try 這個 keyword, 讓系統知道可能會發生例外情況, 需要例外處理程序支援。
2. 至於不同的例外情況, 要做不同的例外處理, 我們必須用 catch 這個 keyword 來加以分別。以我們的例子來說, 當發生了 std::bad_alloc 這種情況時, 請秀出 "Could not allocate memory... Bye" 字串, 然後程式結束 exit(-1);
3. new 就是提供動態記憶體配置 (dynamic storage allocation) 的指令。如果成功配置到記憶體, new 這個 operator 就會傳回一個指標 (pointer), 指向所配置到的記憶體位置。如果失敗了, new operator 就會呼叫 new_handler 函數。這個函數內定的處理方式就是指出發生了一個 bad_alloc 的例外情況。然後再由程式設計師透過例外處理指令 catch 來接手該如何處理這個例外情況。
4. 由於我們要宣告的是一個二維陣列, 因此整個步驟分成兩部份, 首先要求配置 iImageHeight 個一維陣列的指標, 每一個指標都是指向一個資料型態為 unsigned char 的變數。如果成功了, 就將這個陣列的指標存到 ucMatrix 這個變數中。接著, 再利用for 迴圈要求 iImageHeight 個陣列, 每個陣列都有 iImageWidth 個元素 (elements), 每一個元素的資料型態都是 unsigned char。
結束說明 */

注意: 上述程式為了程式的可讀性, 用了全型的空白" "來控制部落格文章的內縮顯示。因此, 如果你要直接複製上述程式到 C++ Builder 執行, 請務必將全型空白" "改成半型空白" ", 否則, 編譯時發出現以下的錯誤訊息。:
[C++ Error] Unit1.cpp(40): E2206 Illegal character ' ' (0xa140)

Monday, September 11, 2006

開啟 JPEG 影像

BCB Professional 版本並不提供直接開啟 JPEG 影像的功能, 要開啟 JPEG 影像, 要自己寫 JPEG 的 decoder, 這個有點難度, 不然就是直接上網找別人寫的程式, 弄懂後, 想辦法和自己的程式結合起來。不過, 如果是 BCB Enterprise 版本, 要開啟 JPEG 影像就容易多了, 只要在程式最前面宣告的部份, 加入:

#include "jpeg.hpp"

至於其他的步驟, 則都和 開啟 BMP 影像 相同。

如果你想要看看 jpeg.hpp 這個檔案的內容, 你可以在

C:\Program Files\Borland\CBuilder6\Include\Vcl\

這個目錄中找到這個檔案。如果你沒有安裝 BCB Enterprise 版, 你可以按這邊 一賭為快

開啟與儲存 BMP 影像

BCB 中, 要寫程式開啟一張 BMP 影像, 非常的簡單, 主要步驟有二:

1. 利用 OpenPictureDialog1->Execute() 來選定你所希望開啟的影像。
OpenPictureDialog 這個對話方塊專門設計用來開啟一張影像的, Execute() 這個method 並不需要任何的傳入值, 當我們用對話視窗選定一個影像檔後, 則會傳回一個 boolean 值 ( true or false), 來表示是否執行成功。如果傳回值是 true, Execute() 就會把你所選擇的檔案名稱 (包刮路徑), 存在FileName 這個字串中。

2. 再利用 Image1->Picture->LoadFromFile(OpenPictureDialog1->FileName)
將影像顯示到 Image1 這個影像物件中。
LoadFromFile 這個 method 的輸入值就是你要開啟的路徑與檔案名稱。

同樣地, 要將影像物件的內容儲存成 BMP 影像檔案, 也是有兩個步驟:

1. 利用 SavePictureDialog1->Execute() 來選定你所希望開啟的影像。

2.
利用 Image1->Picture->SaveToFile(SavePictureDialog1->FileName)
 將影像內容儲存成檔名為 SavePictureDialog1->FileName 的 BMP 檔案中