ソースコード書式
ソースコード書式
この「画像処理ライブラリ」は、【C++】言語で記載され
て居ますが、昭和の時代から【C】言語で自己流に
プログラミングを行った記法をベースにして居る為に多くの
平成以降でのコンピュータ学習系「高校・大学・専門学校」
で教わる方式と異なると感じる部分が有るかも知れませんの
で記法の特徴について説明して行きます!
この「画像処理ライブラリ」は、ソースコードで配布します
ので!自己責任≪自身でソースコードを弄っても内容が変わ
らない自信が有る人は、ご自身が、一番、理解し易い様に
自在に変更は可能です≫で改変して頂いても結構ですが、
オリジナルで無い事は理解して下さい!
1.タブストップとコメント
タイプライタ(機械式・電子式)しか使った事の無い方や、
PC作業でもワープロ(Wordの様なワードプロセッサー
)しか使った事の無い方にはヒョットシテ、「タブストップ
を設定」する意味とか使用方法を理解して無い場合が、
有ると思い「老婆心」から簡単に説明≪キーボードに
「Tab」と言う特殊なキーが有る事は御存知ですね?!
Tabキーを押すと空白文字が自動的に複数個打った様に
移動します!
そしてTabキーを押す度に移動した位置は、横方向に
上下の行でも同じ位置に成る事は理解して居ますね!
タイプライタやWord等の初期設定では、その位置(
ストップ位置)は、8・16・24・32・40・・・と
8文字単位に成って居る筈です!
そして「タブストップを設定」するとは、このストップ位置
を作成する文章(テキスト・コンピュータ言語では文字に
よるプログラミング)の種類毎に都合の良い様に位置を設定
出来る機能で【C言語系では、4・8・12・16・・・と
4文字単位を使用する人が多い】≫、そして私も4文字単位
を使用して居ます?!
次は、コメントです!元々の【C】言語は、
以下のNoteコード機能で示した様に
/* これは、コメントです */
と【/*】で「コメントの始まり」と【*/】で「コメントの終
わり」を示し、フリーフォーマット(自由書式)で記載出来
ます!因みに!
/* これは、行を跨いだコメントです
中身1行目・・・
中身2行目・・・
・・・・
中身の最終行
*/
と複数行も≪/*・・コメント・・*/≫とコメントに成り
ます!さて、【C】言語を進化させた【C++】言語では、
「ポカヨケ」≪この場合、「/*」でコメントが始まるが、
「*/」を書き忘れて記載したプログラムがコンパイラに
依って本文までコメントと見なされる事を防ぐ為の進化し
た手段として「//」から始まり「改行」までをコメントと
する記法が生まれた!≫
// これは、コメントです
a = b * c; // 変数aに変数bと変数cの乗算結果を代入
の様に「左端から始まる本文」を説明するコメントが記載
出来ます!
実は、私は、「コメントが嫌いです」⇒「文法に即して記載
されたプログラミング本体から、意味を読み取れ」と
常常思って居たが、このライブラリは、
会社(もう消滅したがベンチャー企業ADS社)の業務とし
て行ったのと記述量が膨大に成り、不遜にも「自分で記載し
た物は覚えて居る筈」との能力限界を超えた為に
「メモ書き」として必要に成った為に記載したのだ!
但し、本文の中に埋め込む時、出来るだけ、本文と
コメントを離して記載し本文の記述が醜く成る事を避ける
為に、纏まった記載は、本文(C言語文法で記載された部分
でクラス・構造体・「#define」定義の塊)の前には、
行の全てをコメントにしたコメント部を前置する事にしま
した!
// CopyClear.h: CopyClear クラスのインターフェイス
//
//////////////////////////////////////////////////////////////////////
とファイル自体の説明とか
/********************************************************************************************/
/***** 内部で使用するデータ *****/
/********************************************************************************************/
protected:
int m_swDegreeRadian; // 0:ディグリー/ 1:ラジアン
};
性質が変わる「public」属性から「protected」属性に
変わる事を説明するコメントとして記載します!
更に、個別の本文の内容を説明する為にコメントと分かり
易い様に右端にコメントの始まりを以下の様に揃えて
#include "Support.h" // サポート関数定義部
class CopyClear : public Support // クラス定義
{
private:
struct TypeSort { // ソート用データ構造
short key; // ソートキー部
short ix; // ソートインデックス部
}; // 型名「TypeSort」
public:
CopyClear(); // コンストラクタ
virtual ~CopyClear(); // デストラクタ
public: // 画像関数として正規に見せるもの
// 画像クリア/画像コピー
int Clear( // クリア:汎用
TypeArray* pa, // 配列
int data ); // データ
説明の始まりを示します!
私としては、コメントはブロックとして記載しています!
世の中には、説明が必要な極近くにコメントを置いた方が
良いと考える近接主義者がいますが、私は、コメントが
下手に混ざると見難く醜く成ると思ってシマウ人です!
※尚、上記のCode機能の中身は、一旦、Tabキーで
空白が入った物をテキストエディタで空白に変換した物を
使用して居ます!
NoteのCode機能では、Tabストップ設定機能が
有るのかも知れ無いが、
8・16・24・32・40・・・と飛んでしまい不都合
だからです※
2.インデント
ソースコードのインデント(字下げ)としてプログラムの
構造を見易くする為に制御構文の内側にある行などの先頭に
一律に同じ幅の空白を挿入する事をインデントと言い。
この「画像処理ライブラリ」のソースコードでもデータ構造
≪「class」クラス構造・「struct」構造体≫や
制御構文≪「if」構文・「while」構文・「for」構文・
「switch、case、default」構文≫等にインデントを
使用して居ますが、注意深く見て頂ければ、ヒョットシテ
「学校で教えられた方式と異なる」場合が有るかも知れま
せんので先ず、データ構造
class TypeArray // クラス名「TypeArray」
{
public:
TypeArray(); // コンストラクタ
virtual ~TypeArray(); // デストラクタ
int Malloc( int w1, int h1, int v1 ); // 総合型配列メモリ確保&定義
int MallocByte( int h1, int v1 ); // BYTE型配列メモリ確保&定義
int MallocShort( int h1, int v1 ); // short型配列メモリ確保&定義
int MallocInt( int h1, int v1 ); // int型配列メモリ確保&定義
int MallocFloat( int h1, int v1 ); // float型配列メモリ確保&定義
int MallocDouble( int h1, int v1 ); // double型配列メモリ確保&定義
int SetByte( int a, int h1, int v1 ); // BYTE型配列定義
int SetShort( int a, int h1, int v1 ); // short型配列定義
int SetInt( int a, int h1, int v1 ); // int型配列定義
int SetFloat( int a, int h1, int v1 ); // float型配列定義
int SetDouble( int a, int h1, int v1 ); // double型配列定義
int SetByte( void* p, int h1, int v1 ); // BYTE型配列定義
int SetShort( void* p, int h1, int v1 ); // short型配列定義
int SetInt( void* p, int h1, int v1 ); // int型配列定義
int SetFloat( void* p, int h1, int v1 ); // float型配列定義
int SetDouble( void* p, int h1, int v1 ); // double型配列定義
int subset( // 部分配列の定義
TypeArray* orgPtr, // 元へのポインタ
int x, int y, // 始点xy座標
int h1, int v1 ); // 水平・垂直幅
int subsetAdjust( // 部分配列の定義:幅自動調整
TypeArray* orgPtr, // 元へのポインタ
int x, int y, // 始点xy座標
int h1, int v1 ); // 水平・垂直幅
int subsetBMP( // 部分配列の定義:表示用BMP専用
TypeArray* orgPtr, // 元へのポインタ
int x, int y, // 始点xy座標:カラー画素単位
int h1, int v1 ); // 水平・垂直幅:カラー画素単位
int subsetRev( // 部分配列の定義:表示用BMP専用
TypeArray* orgPtr, // 元へのポインタ
int x, int y, // 始点xy座標:個別画素単位
int h1, int v1 ); // 水平・垂直幅:個別画素単位
int get( int x, int y ); // 画素取り出し
double getReal( int x, int y ); // 画素取り出し:実数
void put( int x, int y, int d ); // 画素書き込み
void put( int x, int y, double d ); // 画素書き込み
int getDataInt( int x, int y ); // データ取りだし:4バイト整数
int getDataShort( int x, int y ); // データ取りだし:2バイト整数
void putDataInt( int x, int y, int d ); // データ書き込み:4バイト整数
void putDataShort( int x, int y, int d ); // データ書き込み:2バイト整数
public: // 構造体の内部変数(画像サイズ&画素型)
int adr; // アドレス
int h; // 水平方向大きさ(実範囲)
int v; // 垂直大きさ
int inc; // 水平方向大きさ(垂直増加用)0:1次
char w; // 処理幅(1/2/4BYTE,101:単精度,102:倍精度)
public: // inline 関数
inline int maxX(void){ return( h - 1 ); } // 最大X座標
inline int maxY(void){ return( v - 1 ); } // 最大Y座標
inline int size(void){ return( h * v ); } // 画素数
inline int sizePix(void) // BYTE換算単位サイズ
{ //
if( w == 101 ){ // 単精度なら
return( 4 ); // 4を答えとする
}else if( w == 102 ){ // 倍精度なら
return( 8 ); // 8を答えとする
}else{ // 1/2/4BYTEなら
return( w ); // 左記で算出
} //
} //
inline int sizeMem(void){ // メモリサイズ
return( size() * sizePix() ); } // =画素数×単位サイズ
inline int sizeInc(void){ // BYTE換算増加幅
return( inc * sizePix() ); } // =増加幅×単位サイズ
inline void freeMem(void) // メモリ解放
{ //
if( adr != 0 ){ // メモリ取得済みなら
free( (void*)adr ); // メモリを解放し
adr = 0; // アドレスを初期化
} //
}
inline int check( int x, int y ){ // 検査:全般
if( adr <= 0 || x < 0 || x >= h // アドレスや
|| y < 0 || y >= v ){ // 座標が不正なら、
return( STI_FLG ); // 不正を返す
} //
return( END_STI ); // 正常終了
}
inline int checkXY( int x, int y ){ // 検査:座標
if( x < 0 || x >= h || y < 0 || y >= v ){ // 座標が不正
return( STI_FLG ); // なら、不正を返す
} //
return( END_STI ); // 正常終了
}
inline int getByte( int x, int y ){ // 画素取り出し
return( *( (BYTE*)adr + x + y * inc ) ); } // BYTE単位
inline int getShort( int x, int y ){ // 画素取り出し
return( *( (short*)adr + x + y * inc ) ); } // short単位
inline int getInt( int x, int y ){ // 画素取り出し
return( *( (int*)adr + x + y * inc ) ); } // int単位
inline double getFloat( int x, int y ){ // 画素取り出し
return( *( (float*)adr + x + y * inc ) ); } // 単精度単位
inline double getDouble( int x, int y ){ // 画素取り出し
return( *( (double*)adr + x + y * inc ) ); } // 倍精度単位
inline void putByte( int x, int y, int d ){ // 画素書き込み
*( (BYTE*)adr + x + y * inc ) = d; } // BYTE単位
inline void putShort( int x, int y, int d ){ // 画素書き込み
*( (short*)adr + x + y * inc ) = d; } // short単位
inline void putInt( int x, int y, int d ){ // 画素書き込み
*( (int*)adr + x + y * inc ) = d; } // int単位
inline void putFloat( int x, int y, double d ){ // 画素書き込み
*( (float*)adr + x + y * inc ) = (float)d; } // 単精度単位
inline void putDouble( int x, int y, double d ){ // 画素書き込み
*( (double*)adr + x + y * inc ) = d; } // 倍精度単位
inline BYTE* getPtrByte( int x, int y ){ // 画素アクセスポインタ取出
return( (BYTE*)adr + x + y * inc ); } // BYTE単位
inline short* getPtrShort( int x, int y ){ // 画素アクセスポインタ取出
return( (short*)adr + x + y * inc ); } // short単位
inline int* getPtrInt( int x, int y ){ // 画素アクセスポインタ取出
return( (int*)adr + x + y * inc ); } // int単位
inline float* getPtrFloat( int x, int y ){ // 画素アクセスポインタ取出
return( (float*)adr + x + y * inc ); } // 単精度単位
inline double* getPtrDouble( int x, int y ){ // 画素アクセスポインタ取出
return( (double*)adr + x + y * inc ); } // 倍精度単位
};
ココでは、「TypeArray」クラスの定義を行って居ます!
このクラスが、「画像処理ライブラリ」の画像を意味し、
操作対象に成るデータ構造です!
ここで、よもやま話≪画像だから、「image」とかの名前に
成るのではと思われた読者様も多数いらしゃるでしょう!
元々は、ベンチャー企業ADS社の画像処理装置を動作させ
る為の組み込みコンピュータソフトウェアだったので
元々「TypeImage」と称する構造体「元々C言語しか存在
しない時代に開発された為だからstruct定義です」
アナログの画像同期信号に合わせて駆動するLSI「小さな
会社だったが、最小ロットGA(ゲートアレーと称する半導
体メーカーにカスタム特注品)を作成」とディスクリート
回路で構成された専用のアナログ映像信号をデジタルに
量子化して画像メモリー間で昭和の時代にビデオレートと
当時としては極めて高速動作するハードウェアを制御する為
の情報を格納する構造体が「TypeImage」で画像用のデータ
構造として使用していた時、超高速に動作するハードウェア
では細かい画像処理が出来無いので副次的にCPUで処理す
る為に「TypeArray」構造体を準備したのが、
名称の始まりです!この「struct TypeArray」を使用した
ソフトウェアでの画像処理が、CPUが高速化した昨今、
CPUだけで専用のハードウェアの代りに出来る様にしたの
が「TypeArray」クラスです≫、よそ道に逸れましたが、
「class TypeArray」が、行の先頭(左端)から始まってい
ます!
そして右側に≪// クラス名「TypeArray」≫とコメントを
配してます!次の行に改行したら、行の先頭(左端)に
「{」と波括弧(中括弧)の括弧開くだけを記載し、即、
改行して居ます!C++文法的に対応する「}」波括弧
(中括弧)の閉じ括弧までが、「class TypeArray」範囲
です!
その次も行の先頭(左端)から始まっています!
ココは、異論が有る可能性が有りますが、「public:」と
コノ行以下を「public詰り、クラス外へも参照&使用可能な
定義」で有る事を示す!
重要なキーワードなのでコノ位置にしました!
次に一段、インデントされた所から「TypeArray();」と
クラスが使用する側でコノTypeArrayをデータタイプとして
変数を定義した時に最初に動作する「コンストラクタ」と
呼ばれるメンバー関数の定義が始まります!
次の行で「virtual ~TypeArray(); 」と「デストラクタ」と
呼ばれるメンバー関数の定義が始まります!
デストラクタは、後始末用です!意味はC++言語の
マニュアル(文法規則)を読んで下さい!
次は、「int Malloc(」から「int SetDouble(」メンバー
関数(メソッド)の定義文です!
コンストラクタ・デストラクタと同じく、一段、インデント
された場所から始まり
「Malloc( int w1, int h1, int v1 ); 」と仮引数の並びを
「()」丸括弧(小括弧)で囲み「;」で終えて右方に
コメントを付けています!
次の「int subset(」は、仮引数の並びが1行内に収まら
無いので「,」で本文は改行し行を跨いで記述しています!
先ず、「subset(」と「(」丸括弧(小括弧開く)で改行しま
す!
この記載法の利点としては、「int subset(」と関数名まで
記載した後で改行し、中身の仮引数の並びを分けて記載した
方が分かり易いし、個別に意味をコメントで説明可能だから
です!
恐らく、異論が有るとしたら、「int h1, int v1 ); 」と
コノ仮引数の並び最後の「);」を独立して無い事でしょう
が、私としては、少しでも行数を少なくしたかったのです!
さて、インデントですが、一段で無く複数段下げ、
関数名の始まり依りも後方に配置しました、インデントは
文法で無く美意識です!
だから、見易いと思える方式で記載して居ます!
同じ様に「int subset」とまで記載し、
「(」丸括弧(小括弧開く)を独立行として開き括弧≪
「(」・「[」・「{」・「<」≫等を一行で記載出来ない
文を跨ぐ場合は、改行する記法も≪開き括弧は、右側に有る
べし≫と頭の硬い固定観念の持ち主は、主張するでしょう
が、私は、関数名とか制御構文の場合は、左側で始めても良
いと考えています!勿論、美意識からです!
さて、続きですが、特徴の有る部分は、
「inline int sizePix(void) 」で始まる「sizePix」
メソッドの定義ですが、ココは、インライン定義で実際に
使用した部分に「{}」波括弧(中括弧で囲まれた展開部)を
記述しています!ココは、関数の実体を定義して居るので
「inline」と同じ位置で「{」開き括弧と「}」閉じ括弧の
位置を合わせ、中身を一段インデントし、
「if( w == 101 ){」とif文「ココでは、変数が101数値と
等価検査」し、条件が成立したら「{return( 4 ); }」と
インデントを一段下げて実行する部分を示します!
「){」とif文の条件終わりに実行するブロックの始まりを
示す「{」波括弧(中括弧)は、「)」if文条件終わり
小括弧の直後に付け、アタカも「if( w == 101 ){」の
行自体がif構文の始まり括弧として上方に記載した
括弧開くと解釈して居ます!
この記法でなく「{」を独立して1行だけ括弧開くを表す
事を推奨した記載法も有りますが私は、余分に間延びして
しまうと美意識からコウ記載したのです!
※ここで記載した様に「{」開き波括弧を独立した「{」だけ
で記載して居るのは、クラス定義の本文の記載と
関数(メソッド)の記載だけです!
文法的には、関数の実行分中「{}」でブロックを記載出来
ますが、単にブロックの部分は無く、
if・while・for等の制御構文の中に組み込まれ
ています!※
例外的な記載!
struct TypeSort { // ソート用データ構造
short key; // ソートキー部
short ix; // ソートインデックス部
}; // 型
ここでクラス定義に関しては、「{」開き波括弧を独立した
「{」だけで記載して居る事を説明しましたが、
上記のCodeに載せた「struct」構造体の場合は、
「{」開き波括弧が構造体名の後にと右側に付けて居ます!
勿論、昭和の時代に作成した構造体の名残です!
クラス定義が使える様に成ったC++記載で合わせよう
とも考えたのだが、例外として「struct」構造体は残しまし
た!これは、コレで見慣れていたからです!