Delphi Programming / Object Pascal
サイトのトップページへ リンクのページへ ロゴマーク
[掲載 2004年09月11日] [更新 2018年03月31日] Delphi サンプルプログラム集
   
163_コンポーネントのアイコン作成支援プログラム
動作確認等 Windows 7 U64(SP1) + Delphi XE(UP1) Pro
説明用の画像は更新していない場合あり
163_CreateCompoIconRes.zip [5,885 KB] 2018年05月01日版(EXE同梱)



  • 2018年02月12日 (これより前の履歴は省略)
  • 簡易画像エディタを表示したままでメイン操作画面を操作できるようにした
  • 2018年02月17日
  • 範囲と位置を指定して画像をコピーする機能と,貼り付け位置を指定する機能を追加
  • 画像の描画位置を上下左右にシフトする機能を追加
  • 2018年02月21日
  • 起動オプションの AllSize, FreeSize を廃止.FreeSize オプションと同じ動作仕様にした
  • 2018年03月04日
  • 簡易画像エディタとメイン操作画面を一体化した




コンポーネントのアイコンリソースァイルの作成用プログラム


Delphi のコンポーネントのアイコン用として作成したビットマップ画像から,拡張子が .dcr のリソースファイを作成するプログラムです.扱える正方サイズの画像は 16, 24, 32, 48, 64, 128, 256 だけです.これ以外のサイズの画像も読み込めますが表示や編集に制限があります.

ビットマップ画像を作成したり,画像の本格的な編集等の機能はありませんが,簡単な修正ができるように,簡易的な画像エディタ機能を実装しています.

ビットマップ形式以外の画像,あるいはマルチアイコンもビットマップ形式の画像に変換して読み込むことができます.リソースの画像を個別に保存する機能の他,マルチアイコンファイルとしての保存,マウスカーソルの作成,Glyph 用ビットマップの作成の機能も実装しています.

コンポーネントのアイコンは,画像のサイズ,ビット深さ,リソース名に規則があります.詳しくは以下の [コンポーネント用アイコンの作り方 (2005 以降)] の記事で確認してください.



コンポーネントをインストールする時に,コンポーネントのアイコンリソースファイル (.dcr) がない場合,あるいは該当するコンポーネントのアイコン用のビットマップがない場合は,下図のようなデフォルトのビットマップ画像が使われるようになっています.この画像は Delphi のバージョンによって異なることがあます.
コンポーネントの継承元のコンポーネントにアイコン用のビットマップ画像が存在する場合は,その画像が使われます.



図1
コンポーネントのデフォルトのアイコン
  • 左は Delphi 6.右は Delphi XE
  • Delphi XE の画像は delphicoreide150.bpl 内にある

[備考 1]
本プログラムの実行に必要なのは plCreateDCR.exe だけです.


[備考 2]
添付のプロジェクトファイル plCreateDCR.dpr をコンパイルするには,同梱のファイル類の他に GDI+, TKIcon が必要です.それぞれ以下の記事にダウンロードへのリンクがあります.
Delphi XE2 以降には GDI+ が実装されています.改めてダウンロードする必要はありません.

[備考 3]
コンポーネントのアイコン作成のサンプルとしては 2004年09月11日から公開していましたが,一時公開を中止していました.
2017年12月から再公開して掲載しているのはそのサンプルの改良版です.単なるサンプルプログラムとしてではなく,アプリケーションとして構築しています.ソースコードは掲載していませんが配布ファイルには添付しています.





01_使用方法 - 概要


本プログラムを起動すると,新規のリソース作成状態になります.そこに画像ファイルからビットマップのデータを取り出してリソースとして追加していきます.エクスプローラから画像ファイルを,リソース名のリスト部分にドラック & ドロップすればリソースの画像を追加できます.リソースの入れ替えや削除もできます.
画像の編集機能を実装しているリソースエディタもありますから,本プログラムは本格的な画像の編集機能がない,コンポーネントのアイコン画像専用のリソースエディタといったところです.

左ペインの上が画像の実寸表示ですが,高さが 128 ピクセル以上の画像は縮小表示になります.原寸表示の上にサイズとビット深さを表示していますが,これらの値は編集中の値です,画像を新規作成あるいは読み込んだ時の値ではありません.



図2
新規実行時の画面
図3
添付の DCR ファイルを読み込んで表示
  • ID 名の昇順ソートで表示
  • リソース ID 名の変更は [F2] またはマウス操作

下図では Delphi XE Pro のパッケージファイル dclstd150.bpl を読み込んで表示しています.拡大表示しているのは TButton コンポーネントのアイコンです.



図4
BPL ファイルを読み込んで表示
  • TButton コンポーネントのアイコンを表示中

簡易画像エディタ部分が必要なければ,リストの部分とフォームをリサイズして下図のように使用することもできます.



図5
簡易画像エディタを使用しない場合
  • 画像の加工が必要ない場合はこれでも十分

下の表は操作用ボタンの説明です.ショートカットキー等の設定は一切ありません.
リソース ID の名前の変更操作用のボタンはありません.リソースの名前を選択して [F2] キーを押下するか,マウス操作で編集状態にします.

新規作成の時や終了時に,未保存の編集内容があるかの確認もしません.
[上書き保存] ボタンが有効になっている時は,上書き保存が可能という意味です.未保存の編集内容があるという意味ではありせん.

クリップボードへのコピーは,現在の色数で行いますが,貼り付け先のアプリが必ずしも同じ色数で受け取れるとは限りません.また,他のアプリから貼り付ける場合も,色数がどうなるかはコピー元のアプリの仕様によります.
他のアプリから貼り付けた色数が多い場合,簡易画像エディタで減色することもできますが,他のアプリでの編集結果は,一度ディスクに保存して,そのファイルを読み込んだ方が確実かも知れません.

選択中の各画像の保存はビットマップ形式の他,PNG 形式,ICO (アイコン) 形式,GIF 画像形式,あるいはマウスカーソルを保存の際に選択できます.ICO 形式はシングルアイコンでの保存となります.
透過色の設定や圧縮属性等は全てデフォルトの設定となります.

古い時代のカーソルファイルには 1 ビット (2 色) の画像があります.本プログラムでは 1 ビットの画像は扱いませんので,4 ビット (16 色) にしてから読み込むようにしています.



ボタン画像 機能
新規に DCR を作成する
現在編集中の内容は破棄される.編集中かどうかの確認はしないので注意
起動時には新規作成状態となる
既存の DCR または BPL ファイルを読み込む
エクスプローラからのドラッグ & ドロップでの読み込みも可能
現在編集中の内容は破棄される.編集中かどうかの確認はしないので注意
上書き保存
編集中のリソースが保存済みである場合,その DCR ファイルに上書き保存する
[名前を付けて保存] でアイコンファイルとして保存した場合はその上書き

名前を付けて保存
現在の編集中の状態を DCR ファイルまたはマルチアイコンファイルとして保存
BPL としての保存はできない

新規にリソースを追加して,暫定的なビットマップ画像をセットする
暫定ビットマップは 24 x 24 サイズの 16 色の画像

ファイルから画像をリソースに追加
エクスプローラからのドラッグ & ドロップでの追加も可能
ファイル名の大文字小文字は問わない.自動的に大文字に変換する
PNG 形式,ICO 形式,GIF, CUR 形式の画像もビットマップに変換して追加可能

選択中の ID の画像 (ビットマップ) をリソースから削除
複数選択している場合は,それらを全て削除
選択中の ID のリソースを複製する
複製したリソース ID 名は元の名前の末尾に _COPY_XXX (XXX は数字) を付加
選択中の ID が 1 つだけの場合に有効
選択中の ID の画像を別の画像と入れ替える
PNG 形式,ICO 形式,GIF, CUR 形式の画像もビットマップに変換して入れ替え可能
選択中の ID が 1 つだけの場合に有効
編集中の画像を BMP, PNG, ICO, GIF, CUR 等の形式で保存
選択中の ID が 1 つだけの場合に有効
選択中の ID の画像をクリップボードに,範囲を指定してコピー
選択中の ID が 1 つだけの場合に有効
クリップボードからの貼り付け.貼り付け位置とサイズの変更が可能
選択中の ID が 1 つだけの場合に有効
24 ビット以下のアイコン画像とカーソル画像を読み込む時の透過ピクセルの色
透過ピクセルはこの色にしてから読み込む
画像を減色する時の透明ピクセルの色もこの色を使用する


[備考 1]
拡張子が .BPL のファイルは,パッケージをコンパイルしたファイルです.コンポーネントは必ずどれかのパッケージに登録されています.登録したコンポーネントのアイコン画像 (ビットマップ画像) は,このコンパイル済みパッケージに格納されます.

Delphi の標準のコンポーネントのコンパイル済みパッケージのファイル名は dclstdxx.bpl です.xxx の部分はバージョンによって異なります.Delphi XE では dclstd150.bpl です.これらは Delphi のインストール先の [Bin] フォルダ内にあります.
この .bpl ファイルに Delphi の標準コンポーネントのアイコンが格納されています.本プログラムで読み込んで表示できます. ※ Delphi 3 / 3.1 のコンパイル済みパッケージの拡張子は .dpl です.

[備考 2]
本プログラムでは,dcr ファイルとして保存する際にビットマップファイルヘッダ部分を削除しています.少なくても Delphi XE Pro ではビットマップファイルヘッダ部分があってもコンポーネントのアイコンとして認識してくれるようです.
ビットマップファイルヘッダ部分があると,画像が表示できないリソースエディタがあります.
拡張子が .dcr のリソースを表示できないリソースエディタでも,拡張子を .res に変更すれば表示できるようになります.逆に本プログラムの場合,リソースファイルの拡張子を .dcr にすれば,リソースファイル内の,リソースの型が IMAGE_BITMAP または RT_BITMAP のビットマップ画像を読み込んで表示できます.




02_使用方法 - アイコン画像を読み込む時の透過ピクセルの色


拡張子が .bmp であるビットマップ画像の透過設定は透過するピクセルを色で指定します.これは実行時の設定です.拡張子が .gif の 画像も透過ピクセルを色で設定しますが,この情報は画像データとして格納されています.

拡張子が .ico, .cur の画像には,透過描画するピクセルの情報が格納されています.透過色としての情報はありません.昔のマウスカーソルには 1 ビットの画像がありました.2 色ですが,実際に使用されいたのはほとんど白と黒です.2 色であっても透過ピクセルの情報が格納されているので透過表示できます.2 色のどちらかが透過色というわけではありません.

本プログラムの [透過ピクセルの色] は,アイコン画像を読み込む時の,この透過ピクセルの色を設定するためのものです.デフォルトの色を設定していますが,昔は「ピンク色」も多く使用されていたようです.

コンポーネント用アイコンのビットマップ画像の透過設定は,ビットマップ画像のデフォルトの設定が使われます.つまり,32 ビットのアルファチャンネル付きのビットマップ画像では「透明色」が,それ以外は左下のピクセルの色が透過表示となります.しかし,アイコン画像では必ずしも左下のピクセルが透過ピクセルとは限りません.


図6
透過ピクセルの色
  • 透過ピクセルの色を変更するには,クリックして色の選択ダイアログを表示する

[備考 1]
透過ピクセルの色の設定の機能は,アイコン形式の画像とマウスカーソルの画像を読み込む際の設定です.また,32 ビットの画像を減色する際,透明ピクセルもこの色で塗り潰しします.


[備考 2]
画像の重ね描画や合成にはアルファチャンネル付きの 32 ビットの画像が不可欠です.このことを考えると,透過ピクセルの色は淡く薄い色の方が良いと思われます.
透過ピクセルの色を白にすると,画像の白のピクセルも透過してしまいます.黒にすると黒のピクセルが透過状態になります.


[備考 3]
拡張子が .ICO であるアイコン画像の作成編集ソフトであれば,透過ピクセルを透明色として扱っても問題ありませんが,本プログラムはコンポーネントのアイコン画像の作成,編集用のプログラムです.コンポーネントのアイコン画像は 拡張子が .bmp のビットマップ形式です.
24 ビット以下のビットマップ形式の画像には透明色は存在しません.そのため,透過ピクセルに何らかの色を設定する必要があります.





03_使用方法 - 簡易画像エディタ


本プログラムには,機能は乏しいですが簡単な画像エディタを実装しています.
本プログラムでは,24 ビット以下の画像は左下のピクセルの色を透過色として扱いますが,32 ビットの画像はアルファチャンネル付きのビットマップとして扱います.したがって,左下のピクセルの色を透過表示するわけではありません.透過表示するのは「透明色」のピクセルです.

下の表は簡易画像エディタの操作用ボタンです.ショートカットキー等の設定は一切ありません.半透明の色を設定する機能はありません.



ボタン画像 機能
1 つ前の編集状態の画像に戻す
画像に対しての操作をしない通常の状態にする
ピクセルの色の変更.ドラッグすれば連続したピクセルの色の変更となる

画像の領域の塗り潰し

カラーピッカー
拡大表示している画像の,指定ピクセルの色を取得する

画像の明るさ,ガンマ値,グレイスケール化の設定
設定用のダイアログを表示する

左右を反転した画像にする

上下を反転した画像にする

90 度回転した画像にする.回転方向は時計回り
[Ctrl] キーを押した状態でクリックすると反時計回りに 90 度回転

画像の描画位置を上下左右にシフトさせる

画像に文字を重ね描画する
文字だけの画像にすることも可能

拡大表示している画像のグリッド線の表示トグル
[Ctrl] キーを押したままクリックすると,全てのリソース画像に対する設定となる
グリッドのセルのサイズが小さい時は表示しない

拡大表示している画像のグリッド表示を拡大
[Ctrl] キーを押したままクリックすると,全てのリソース画像に対する設定となる

拡大表示している画像のグリッド表示を縮小
[Ctrl] キーを押したままクリックすると,全てのリソース画像に対する設定となる





04_使用方法 - 16 色と 256 色画像のピクセルの色変更とパレット操作


16 色 (4 ビット) と 256 色 (8 ビット) の画像のピクセルは色の値ではありません.パレットの番号 (インデックス) です.パレットにない色は使用できません.
画像のピクセルの色を変えるには,パレットから色を選択し,その色を使用しますが,定義済みのパレットの色を変更する方法もあります.また,パレットに色を追加してそれを使用する方法もあります.

下図はパレットの色を変更する例です.右側のパレット表示で,変更するパレットの色の部分をダブルクリックします.すると色の選択ダイアログが現れます.そのダイアログで設定します.
パレットの色を変更すると,画像の該当ピクセルの色も変わります.



図7
パレットの色の変更方法
  • 変更するパレットの色をダブルクリック
  • 色選択ダイアログが表示されるので設定
図8
変更結果

パレットに色を追加するには,パレットの色が定義されていない場所をダブルクリックします.すると色の選択ダイアログが現れます.そのダイアログて色を選択します.

パレットの構成は,画像の描画関係の操作を実行すると再構築するようにしています.したがって,追加した色がパレットの末尾に表示されるとは限りません
パレットの操作や動作仕様はソフトによって違いがあります.ユーザ独自のパレット作成する機能や,パレットを保存したり読み出して利用する機能を実装しているソフトもあります.本プログラムでは,使用する色だけをパレットに表示するという方針にしています.したがって,色を追加してもその色を使用しなければパレットから削除されます.

下図はパレットに「赤」を追加した状態です.上の図のパレットに「赤」が追加されているのが確認できます.この追加した色で背景を塗り潰しています.

パレットに空きのインデックスがない画像の場合,色の追加はできません.
また,16 色の場合,追加する色によってはパレットの再構成が正常に行われないことがあり,既存の色が変わってしまうことがあります.



図9
パレットに色を追加する方法
  • 色の定義がないパレット部分をブルクリック
  • 色選択ダイアログが表示されるので設定
図10
追加した色で塗り潰し
  • パレットの再構成が行われ,追加した色の位置が変わる




05_使用方法 - 画像の明るさとコントラストとグレイスケール化


画像の明るさとコントラストも設定できます.また,グレイスケール化もできるようにしています.
まず明るさを設定するようになっています.その明るさを設定した画像に対してコントラストを処理します.グレイスケール化も同じです.

コントラストは実際にはガンマ値を設定しています.TSpinEdi に明るさとガンマ値を表示していますが,これは明るさとガンマ値の定義の値ではありません.処理の程度を確認するための値です.コントラストやガンマ値に負の値はありません.



図11
処理前の画像
図12
コントラストを上げた結果
図13
グレイスケール化
  • Disable な画像 (Enabled プロパティの値が False の時の画像) に使用できる




06_使用方法 - 画像のサイズと色数変更と半透明ピクセルの処理


[サイズ・色数変更] ボタンをクリックすると設定用のダイアログが現れます.このダイアログで変更します.


[備考]
アイコン画像の作成編集ソフトの多くは,画像のサイズや色数 (色のビット深さ) を変更する際には別の画像にするようになっていますが,本プログラムでは現在の画像を変更します.
元の画像を残しておきたい場合は,[選択リソースを複製] で複製した画像を操作します.



図14
画像のサイズと色数 (ビット深さ) の変更

簡易画像エディタで表示中の画像が 32 ビットの場合,サイズと色数変更のダイアログは下図のように透明ピクセルの処理の設定項目が追加されます.

これは減色処理の時のアルファシャドウと呼ばれる画像の半透明の影の部分の処理方法を設定します.減色する時に影の部分を除外すると,結果の画像の体裁がよくなることがあります.

この処理は R, G, B の値が全て 0 のピクセルを処理します.つまり,黒の半透明ピクセルの処理です.画像には黒ではない色の半透明のピクセルもあります.それらの減色後のピクセルの色は背景色である透過ピクセルの色の影響を受けます.したがって,この処理をしても,減色した画像の体裁を整えるにはある程度の操作が必要なことがあります.
アルファ値のレベル (閾値) を $FF (= 255) にすると,「黒」も透明になってしまうので 255 には設定できないようにしています.

減色の時に,透明ピクセルを塗り潰す色は [透明ピクセルの色] で設定した値です.
この色は,減色処理の際に背景色としても使用するようにしています.そうすることにより,画像の半透明のピクセルを中間的な色にすることができます.



図15
デフォルトの設定で減色
  • 画像の右側に影がある
図16
半透明の黒を全て背景色で塗り潰した場合
  • 影の部分が描画されていない

透明ピクセルの設定の一番下に [RGB ( 0, 0, 0 ) 以外も透明にする] という項目があります. これをチェックすると,背景の半透明,透明ピクセルだけでなく画像全体の半透明のピクセルが対象となります.画像の周辺が半透明になっている画像があります.
そのような画像の場合,この方法で減色すると体裁のいい画像となることがあります.当然ですが,透明にするアルファ値の閾値を 255 にすると画像は表示されなくなってしまうので 255 には設定できないようにしています.

減色した時に透明ピクセルの塗り潰しに使われる色は透過ピクセルの色です
したがって,以下の図のように,減色操作をする前に透過ピクセルの色を変更しておけば,その色が背景色となります.
下図は透過ピクセルの色をグレー系の色にして,添付の 256 x 256 の 32 ビットの画像を 256 色に減色した結果です.減色の際に半透明のピクセルを透明にはしていません.デフォルトの設定で減色しています.左側の実寸表示は縮小表示となっています.高さは 128 を超えるサイズの画像は縮小表示となります.



[備考]
アルファチャンネル付きの画像を 24 ビット以下に減色する時,アルファ値を完全に無視する場合,そのピクセルは当然「黒」になります.
あるピクセルの ARGB の値が ($55, 0, 0, 0) だった場合,アルファがなくなるわけですから RGB の各値は (0, 0, 0) となります.これは「黒」です.



図17
256 x 256 の 32 ビットの画像を 256 色に減色した結果
  • 透過ピクセルの色以外はデフォルトの設定のままで減色




07_使用方法 - 画像の描画位置の調整


画像の描画位置を上下左右に,ピクセル単位でシフトする機能です.
以下のダイアログのボタンクリック,または矢印キーの操作で調整します.位置調整用ボタンは,クリックする位置によって上下左右のシフトとなります.ボタンを押し続けると連続してシフトします.

TSpeedButton, TBitBtn の Glyph 用の画像の描画位置,あるいは TToolBar の TToolButton 等の画像を少しだけ上下左右にシフトして表示したい時等に利用できるかも知れません.



図18
元の画像

上の図の状態で左にシフトして,更に上下を反転させたのが下図です.



図19
描画位置の調整結果




08_使用方法 - 位置と範囲指定のコピーと貼り付け


クリップボードへのコピーは,選択中のリソース画像を位置とサイズを指定してのコピーとなります.貼り付けの時も下図のように位置とサイズ指定の貼り付けとなります.
下図は,前項の説明で使用した画像の一部分をコピーして,別の画像に貼り付けしようとしているところです.位置とサイズの調整は前項の機能と同じで,ボタンクリックあるいは矢印キーを使用します.サイズの変更は [Shift] キーと矢印キーを使用します.



[備考 1]
クリップボードの画像を貼り付けた時に,透過状態になるピクセルは下図のように透過色のピクセルだけです.当然ですが,コピー元のアプリケーションが透明色の情報を保持した状態でクリップボードにコピーしている必要があります.

透過色のピクセルを,他の画像に貼り付けた時に透過状態にするためには,画像を 32 ビットに変換して,透過色を透明色にしてからコピーします.ただし,貼り付け側のアプリケーションが必ずしも透明色を透過状態で貼り付けするとは限りません.


[備考 2]
16 色の画像に貼り付ける場合,画像の色数を 256 色以上にしてから貼り付けて,貼り付けた後に減色すると画質の低下を低減できることがあります.




図20
貼り付けの設定
  • 画像の重ね描画ということになる




09_使用方法 - 画像に文字を追加描画


[文字を追加描画] のボタンをクリックすると,表示中の画像に文字を描画するための設定用ダイアログが表示されます.このダイアログで文字を追加描画できます.
これは文字を画像にして重ね描画するものです.

描画した文字だけの画像とすることもできます.記号の文字を画像にしたアイコン等を作成する時にも利用できるかも知れません.下図はその例です.Webdings, Wingdings, Wingdings 2, Wingdings 3 等には数は多くはありませんが,絵文字や図形等の文字があります.

画像の描画位置の調整にラバーバンドは使用しません.右側にあるボタンで操作します.ボタンの左側をクリックすると左側に,右側をクリックすると右に移動します.TSpinButton と同じように,ボタンを押し続けると連続移動します.

設定可能な文字のサイズは画像のサイズによって制限をしています.また,フォントの種類文字セットによっては,文字の入力欄,あるいは画像への描画も異なる文字となることがあります.



図21
文字の描画




10_使用方法 - マルチアイコンファイルとして保存


アプリケーションのアイコンは基本的にマルチアイコンが必要です.本プログラムでも,画像さえ用意すればマルチアイコンファイルとして保存できます.

マルチアイコンファイルとして保存するには,[名前を付けて保存] のダイアログで,下図のように [マルチアイコン] を選択して保存します.読み込んでいる画像全てを含む ICO 形式のマルチアイコン画像ファイルとしての保存となります.
ファイルへの格納はリソース名の順になります.格納の順番を変更したい場合はリソース名を変更してください.マルチアイコンファイル内には,情報としてのリソース名は格納されません.

画像の左下のピクセルと同じ色のピクセルを透過ピクセルとして処理して保存しますが,32 ビットの画像は透過色だけを透過処理します.256 x 256 サイズの画像は PNG 形式の画像として格納します.
選択中のリソース ID の画像を単独で保存する場合は,全てビットマップ形式での保存です.

マルチアイコンファイルとして保存すると,[上書き保存] は保存したマルチアイコンファイルに対する上書き保存となります.




図22
マルチアイコンファイルとして保存する




11_使用方法 - ホットスポットの設定とカーソルファイルとしての保存


マウス用のカーソルファイルとして保存するには,[編集中の画像を保存] のボタンをクリックして [カーソルファイル保存] を選択します.
すると,ホットスポットの設定ダイアログが表示されます.そのダイアログでホットスポットを設定または確認してから保存します.

元の画像のビット深さとは関係なく,カーソルファイルはアルファチャンネル付きの 32 ビットの画像として保存します.透過色は透明色に変換してから保存するようになっています.これは Windows XP 以降のカーソルファイルのデフォルトの仕様です.

32 x 32 サイズ以外のカーソルファイルも作成できますが,画面に表示する時は 32 x 32 に拡大または縮小表示されます.拡大または縮小表示されると,設定したホットスポットが予期しない位置になってしまいます.マウスカーソルは 32 x 32 の画像を使用してください.



図23
マウス用のカーソルファイルとしての保存
図24
ホットスポットの設定用ダイアログ
  • 画像は添付の ARROW2.CUR ファイル (元は 1 ビット画像)

ディスプレイの設定が [大 - 150%] あるいは [特大 - 200%] の時に使用される 48 x 48, 64 x 64 サイズの画像を含めて,マルチカーソルファイルとしての保存もできます.
上の図のダイアログでホットスポットを設定したら保存しないでダイアログを閉じます.その操作を保存する画像全てに行った後,[名前を付けて保存] で [マルチカーソル] を選択して保存します.
マルチカーソルファイルとして保存すると,[上書き保存] は保存したそのカーソルファイルに対する上書き保存となります.






12_使用方法 - Glyph 用ビットマップの作成と保存


Glyphi 用のビットマップ画像を作成するには,あらかじめ,Glyph 用のビットマップに格納する画像を読み込んでおきます.この時,画像のサイズと色数は全て同じものとします.異なるサイズと色数の画像は読み込んでも利用できませんが,簡易画像エディタで変更することもできます.
その中からどれか 1 つを選択して,[編集中の画像を保存] のボタンをクリックします.メニューから [Glyph 用ビットマップ作成保存] を選択すると下図のようなダイアログを表示します.このダイアログで作成して保存します.

左のペインには,最初に読み込んだ画像と同じサイズと同じ色数の画像をリスト表示します.この中の画像を選択して追加していきます.Glyph 内の画像の順番を入れ替える機能はありません.画像を削除して追加し直してください.
Glyph 用のビットマップの状態での編集はできません.分割して取り込みんで使用することになります.それらの画像を .dcr ファイルとして保存しておけば使い回しができます.



[備考 1]
Glyph 用のビットマップは 24 ビットの画像で作成した方が無難です.複数の画像を結合するわけですから,色数が 16 色あるいは 256 色内に収まるとは限りません.必然的に減色され,ピクセルの色が違う色になるなど,画質が劣化する可能性があります.


[備考 2]
下図のダイアログで使用している 2 つの操作用ボタン (TSpeedButton) の Glyph 用ビットマップ画像は,本プログラムで作成しています.



図25
Glyph 用ビットマップ作成用ダイアログ
  • 添付の Images_Glyph.dcr を読み込んで操作
  • 右の上は作成した Glyph 用ビットマップ画像
  • その下は動作確認用の
    TBitBtn と TSpeedButton

上の Glyph 用ビットマップ作成の説明で使用している画像は,アルファシャドウを持つ PNG 画像から以下の手順で作成しています.

  • (1) PNG 画像ファイルをディスクから読み込み (透過ピクセルの色はデフォルトのまま)
  • (2) アルファ値が 254 以下のピクセルを透明色にする設定で 256 色に減色
  • (3) 背景を「ピンク色」で塗り潰し
全ての画像でこの処理をして,Images_Glyph.dcr という名前で保存しました.このファイルを添付しています.




13_使用方法 - アイコン画像作成編集ソフト等との連携


アプリケーションの起動パス名等を記述したテキストファイルを使用して,外部アプリの起動するためのボタンを配置していましたが,2018年02月22日の更新で廃止しました.





14_使用方法 - 起動オプション


起動オプションは 1 つだけで,起動時に読み込むファイルです.この [コンポーネントのアイコン作成支援プログラム] で読み込み可能なファイルであれば以下のように指定できます.


plCreateDCR.exe D:\000\plCompoIconRes.dcr



図26
起動オプションの指定例




15_コンポーネントのアイコンとして使用可能なサイズと色数


Delphi 7 まではコンポーネントのアイコンとして使用可能なのは 24 x 24 の 16 色 (4 ビット) のビットマップだけでした.Delphi 2005 では 16 x 16, 24 x 24, 32 x 32 の 256 色 ( 8 ビット) までのビットマップ画像が使用可能になりました.Delphi 2009 では Unicode 化とともに画像処理関係の機能も充実しました.そこで Delphi XE ではどうなのかテストしてみました.
テストしたのは 32 ビットのアルファチャンネル付きのビットマップ画像です.下図は,作成した画像ファイルをエクスプローラで表示しているところです.



図27
作成したアルファチャンネル付きの 32 ビットのビットマップ画像
  • 透過表示するピクセルの色は透明色にしている
  • 16 x 16 の一部のアイコンを透明色にするのを忘れている

実際にコンポーネントのアイコンとして使用して,コンポーネントを登録した結果です.
コンポーネントのソースコードは後述のサンプルのコードを使用しています.

下図はコンポーネントパレットに表示されたアイコンです.
その下の図はツールパレットでのアイコン画像表示です.順番に大,中,小のアイコンです.この大,中,小は [ツール] [オプション] のダイアログの [ツールパレット] [表示] の大中小のラジオボタンで指定します.

32 ビットのアルファチャンネル付きのビットマップ画像が,コンポーネントのアイコンとして使用可能であることが確認できました.同じアルファチャンネル付きの画像であっても,透過したい部分を透明色にしないと元の色で表示されます.
アルファチャンネルなしの 32 ビットと 24 ビット以下のビットマップの場合は,左下の色を自動的に透過表示してくれます.


図28
コンポーネントパレット
図29
32 x 32 サイズのアイコン表示のツールパレット
図30
24 x 24 サイズのアイコン表示のツールパレット
図31
16 x 16 サイズのアイコン表示のツールパレット




16_unitResFile を利用したリソースファイル作成の基本コード


[コンポーネントのアイコン作成支援プログラム] では以下のサンプルでも利用している unitResFile を利用 を使用しています.
unitResFile を利用してリソースファイルを作成する基本的なコードが以下に示すサンプルコードです.このサンプルでは,言語識別子とリソース ID 名を指定して新規にリソースを追加して,次にビットマップ画像ファイルからリソースとしてのビットマップデータをセットします.

このサンプルでは.lock32.bmp ファイルのビットマップだけをリソースとして,CompoIconRes.dcr というファイル名で保存しています.

リソースは,システムのロケールが日本語の場合,言語識別子が LANG_JAPANESE のものが使われます.言語識別子の表示はリソースエディタによって違い,1041, Japanese あるいは「日本語 (日本)」等の表示になります.
言語識別子が LANG_NEUTRAL の画像があるとそれが優先的に使われます. 



図32
実行時の画面

リスト1
コンポーネントのリソースファイル .dcr 作成の基本コード
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ExtCtrls, unitResFile, unitResourceDetails;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

//=============================================================================
//  unitResFile を利用したリソースファイル .dcr 作成の基本コード
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  LdcrResFilePath : string;
  LResModule      : TResModule;
  LLanguage       : Word;
  LItemName       : string;
  LResType        : string;
  LbmpFilePath    : string;
begin
  //リソースに格納するビットマップ画像のファイル
  LbmpFilePath    := ExpandFileName('clock32.bmp');
  //作成するリソースファイルの名前(拡張子は.dcr)
  LdcrResFilePath := ExpandFileName('CompoIconRes.dcr');

  LLanguage := MAKELANGID(LANG_JAPANESE, SUBLANG_DEFAULT);
  LItemName := ChangeFileExt(ExtractFileName(LbmpFilePath), '');
  LResType  := UIntToStr(Cardinal(RT_BITMAP));

  //リソースのインスタンスを生成
  LResModule := TResModule.Create;
  try
    //ビットマップのリソース項目をを新規追加
    TResourceDetails.CreateNew(LResModule, LLanguage,  LItemName);

    //追加したリソース項目にビットマップのデータとリソースの型をセット
    LResModule.ResourceDetails[0].data.LoadFromFile(LbmpFilePath);
    LResModule.ResourceDetails[0].ResourceType := LResType;

    LResModule.SaveToFile(LdcrResFilePath);
  finally
    FreeAndNil(LResModule);
  end;
end;

end.




17_unitResFile を利用したリソースファイル .dcr の作成


前項よりも少し本格的なリソースの作成サンプルです.
このサンプルでは 4 つのコンポーネントのアイコン画像をリソースとして格納します.各々のコンポーネントのアイコン画像として,16 x 16, 24 x 24, 32 x 32 のサイズの 256 色のビットマップ画像を格納します.それを plCompoIconRes.dcr という名前で保存します.

本ページで提供している [コンポーネントのアイコン作成支援プログラム] は,このサンプルが実行する動作を GUI 操作で行えるようにしたプログラムです.




図33
実行時の画面
  • TEdit に表示しているのが保存ファイル名

リスト2
unitResFile を利用したリソースファイル .dcr の作成
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ExtCtrls, unitResFile, unitResourceDetails;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Edit1: TEdit;
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    { Private 宣言 }
    FdcrResFilePath : string;
    FResType        : string;
    FResModule      : TResModule;
    FLanguage       : Word;
    procedure AddBmpResourceFromSteam(AStream: TMemoryStream; AItemName:
      string);
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

//=============================================================================
//  フォーム生成時の処理
//=============================================================================
procedure TForm1.FormCreate(Sender: TObject);
begin
  Edit1.Text := '.\plCompoIconRes.dcr';

  //リソースのインスタンスを生成
  FResModule := TResModule.Create;

  FLanguage  := MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT);
  FResType   := UIntToStr(Cardinal(RT_BITMAP));
end;

//=============================================================================
//  フォーム破棄時の処理
//=============================================================================
procedure TForm1.FormDestroy(Sender: TObject);
begin
  FreeAndNil(FResModule);
end;

//=============================================================================
//  コンポーネントのアイコン用のリソースファイルを作成
//  既存のファイルが存在する時は上書き保存
//
//  格納するビットマップはコード内で指定している
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  LsrcStream : TMemoryStream;
  LItemName  : string;
  LFileList  : TStringList;
  LItemNo    : Integer;
begin
  FdcrResFilePath := ExpandFileName(Trim(Edit1.Text));

  LFileList  := TStringList.Create;
  LsrcStream := TMemoryStream.Create;
  try
    LFileList.Add('..\BmpImages\TplClock.bmp');
    LFileList.Add('..\BmpImages\TplClock16.bmp');
    LFileList.Add('..\BmpImages\TplClock32.bmp');

    LFileList.Add('..\BmpImages\TplBookEdit.bmp');
    LFileList.Add('..\BmpImages\TplBookEdit16.bmp');
    LFileList.Add('..\BmpImages\TplBookEdit32.bmp');

    LFileList.Add('..\BmpImages\TplChartBar.bmp');
    LFileList.Add('..\BmpImages\TplChartBar16.bmp');
    LFileList.Add('..\BmpImages\TplChartBar32.bmp');

    LFileList.Add('..\BmpImages\TplAccount.bmp');
    LFileList.Add('..\BmpImages\TplAccount16.bmp');
    LFileList.Add('..\BmpImages\TplAccount32.bmp');

    for LItemNo := 0 to LFileList.Count - 1 do begin
      LsrcStream.Clear;
      LsrcStream.LoadFromFile(LFileList[LItemNo]);
      LItemName := ChangeFileExt(ExtractFileName(LFileList[LItemNo]), '');

      //リソースを追加
      AddBmpResourceFromSteam(LsrcStream, LItemName);
    end;

    //ソートして保存
    FResModule.SortResources;
    FResModule.SaveToFile(FdcrResFilePath);
  finally
    FreeAndNil(LsrcStream);
    FreeAndNil(LFileList);
  end;
end;

//-----------------------------------------------------------------------------
//  ビットマップを格納したメモリストリームからビットマップリソースを作成
//
//  AStream   : ビットマップのデータを格納したメモリストリーム
//  AItemName : リソースの項目に付ける名前
//-----------------------------------------------------------------------------
procedure TForm1.AddBmpResourceFromSteam(AStream: TMemoryStream; AItemName: string);
var
  LCount     : Integer;
  LHeadStr   : array[0..1] of AnsiChar;
  LresStream : TMemoryStream;
begin
  //リソースIDは文字列で強制的に大文字にしてしまう
  AItemName := UpperCase(AItemName);

  //同じ名前のIDは登録できないのでチェック
  for LCount := 0 to FResModule.ResourceCount - 1 do begin
    if FResModule.ResourceDetails[LCount].ResourceName = AItemName then begin
      exit;
    end;
  end;

  LresStream := TMemoryStream.Create;
  try
    //ビットファイルヘッダ部の存在確認
    AStream.Position := 0;
    AStream.Read(LHeadStr, 2);
    if LHeadStr = 'BM' then begin
      AStream.Seek(SizeOf(TBitmapFileHeader), soBeginning);
      LresStream.Position := 0;
      LresStream.CopyFrom(AStream, AStream.Size - SizeOf(TBitmapFileHeader));
    end else begin
      AStream.Position    := 0;
      LresStream.Position := 0;
      LresStream.CopyFrom(AStream, AStream.Size);
    end;

    //ビットマップのリソース項目をを新規追加
    TResourceDetails.CreateNew(FResModule, FLanguage, AItemName);

    //追加したリソース項目にストリームのデータとリソースの型をセット
    LCount := FResModule.ResourceCount - 1;
    FResModule.ResourceDetails[LCount].data.LoadFromStream(LresStream);
    FResModule.ResourceDetails[LCount].ResourceType := FResType;
  finally
    FreeAndNil(LresStream);
  end;
end;

end.


以下は,上のコードで作成したコンポーネントのアイコン画像を使用するコンポーネントのソースコードの例です.コンポーネントとして Delphi XE に登録した結果が下の図です.



図34
登録されたコンポーネント類

リスト3
テスト用のコンポーネントのコード
unit plCompoIconRes;

interface

uses
  Windows, Classes;

type
  TplAccount = class(TComponent);

  TplBookEdit = class(TComponent);

  TplChartBar = class(TComponent);

  TplClock = class(TComponent);

procedure Register;

implementation

procedure Register;
begin
  RegisterComponents('TestPage', [TplAccount]);
  RegisterComponents('TestPage', [TplBookEdit]);
  RegisterComponents('TestPage', [TplChartBar]);
  RegisterComponents('TestPage', [TplClock]);
end;

end.




18_ビットマップのサイズとビット深さのチェック


[コンポーネントのアイコン作成支援プログラム] ではリソースに格納するビットマップのサイズとビット深さを取得して表示しています.それには以下のようなコードを使用しています.

ビットマップファイルヘッダの部分は 40 バイトの固定ですが,ビットマップファイルインフォヘッダ部は 3 種類あります.ビットマップのサイズとビット深さを取得するだけであれば,以下のサンプルのように TBitmapInfoHeader のサイズだけを取得すれば十分です.



図35
実行結果

リスト4
ビットマップのサイズとビット深さのチェック
implementation

{$R *.dfm}

//=============================================================================
//  フォーム生成時の処理
//=============================================================================
procedure TForm1.FormCreate(Sender: TObject);
begin
  Edit1.Text := '..\BmpImages\TplChartBar32.bmp';
end;

//=============================================================================
//  ビットマップ画像のサイズとビット深さをチェックする例
//
//  ビットマップインフォヘッダには以下の3種類がある
//  幅,高さ,ビット深さしか取得する必要がないのでTBitmapInfoHeaderだけで十分
//    TBitmapInfoHeader
//    TBitmapV4Header
//    TBitmapV5Header
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  LBmpFilePath   : string;
  LsrcStream     : TMemoryStream;
  LHeadStr       : array[0..1] of AnsiChar;
  LBmpInfoHeader : TBitmapInfoHeader;
  LBmpWidth      : Integer;
  LBmpHeight     : Integer;
  LBmpCount      : Integer;
begin
  ListBox1.Items.Clear;

  LBmpFilePath := ExpandFileName(Trim(Edit1.Text));

  LsrcStream := TMemoryStream.Create;
  try
    LsrcStream.LoadFromFile(LBmpFilePath);

    //ビットマップかどうかのチェック
    LsrcStream.Read(LHeadStr, 2);
    if LHeadStr <> 'BM' then exit;

    LsrcStream.Seek(SizeOf(TBitmapFileHeader), soBeginning);
    LsrcStream.ReadBuffer(LBmpInfoHeader, SizeOf(TBitmapInfoHeader));

    //ビットマップのサイズとビット深さを取得
    LBmpWidth  := LBmpInfoHeader.biWidth;
    LBmpHeight := LBmpInfoHeader.biHeight;
    LBmpCount  := LBmpInfoHeader.biBitCount;

    ListBox1.Items.Add('biWidth  : ' + IntToStr(LBmpWidth));
    ListBox1.Items.Add('biHeight : ' + IntToStr(LBmpHeight));
    ListBox1.Items.Add('bitCount : ' + IntToStr(LBmpCount));
  finally
    FreeAndNil(LsrcStream);
  end;
end;




19_ビット深さを指定したクリップボードへのコピーと貼り付け


Delphi では次のようなコードでビットマップをクリップボードにコピーしたり,クリップボードから貼り付けることができます.この時,クリップボードの CR_BITAMP, CF_DIB フォーマットには同じデータが格納されるようです.CF_BITMAP はデバイス依存のビットマップです.64 ビットのカラーを扱うビデオボードもありますが,現在の Windows 7 の環境では 32 ビットのカラーと考えて差支えないと思います.


  Clipboard.Assign(TBitmap);
  TBitmap.Assign(Clipboard);


CF_DIB にはデバイス非依存のビットマップのデータをセットすることができます.そうすると,クリップボードからデータを取得する際,CF_DIB のデータを取得すればデバイスに依存しないビットマップのデータを取得することが可能になります.以下のコードはその例です.
このサンプルでは,指定したビット深さの画像を読み込んでクリップボードにコピーします.そしてそのクリップボードのビットマップデータを取得してディスクに保存します.コピーした時と同じビット深さのビットマップがクリップボードから取得できることが確認できます.

保存したビットマップ画像のビット深さはファイルのプロパティのダイアログでも確認できます.
本テストで使用している添付のビットマップ画像は,4 ビット (16 色) の画像から作成しています.したがって, 基本的にビット数による画像の違いはありません.

このサンプルコードでは,32 ビットのアルファチャンネル付きの画像は,アルファ値を保持したままでコピーできます.受け取る側でも,CF_DIB のデータを取得すればアルファチャンネル付で取得できます.[コンポーネントのアイコン作成支援プログラム] では本サンプルと同じコードを使用してクリップボードのデータを処理しています.



[備考 1]
ビットマップをクリップボードにコピーすると,CF_BITMAP, CF_DIB のどちらにもビットマップのデータが格納されます.CF_BITMAP のデータはシステムによって決まりますが,本サンプルの動作結果で分かるように,CF_DIB のデータはコピーする側のアプリケーションによって決まります.


[備考 2]
このサンプルでは,他のアプリでコピーした CF_DIB のビットマップも [Paste] ボタンで取得して確認できます.ただし,保存名は選択しているラジオボタンによって自動的に決まります.



図36
実行時の画面
  • ラジオボタンを選択
  • [Copy] ボタンをクリック
  • [Paste] ボタンをクリック
図37
[ファイルのプロパティ] ダイアログで確認
  • コピーした時のビット深さと同じになる

リスト5
ビット深さを指定したビットマップのクリップボードへのコピーと貼り付け
Halbow 資料館のサンプルコードを利用している
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ComCtrls, ExtCtrls;

type
  TForm1 = class(TForm)
    Panel1: TPanel;
    Button1: TButton;
    Button2: TButton;
    Image1: TImage;
    RadioGroup1: TRadioGroup;
    ListBox1: TListBox;
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Private 宣言 }
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

uses
  Clipbrd;

{$R *.dfm}

//=============================================================================
//  フォーム生成時の処理
//=============================================================================
procedure TForm1.FormCreate(Sender: TObject);
begin
  RadioGroup1.ItemIndex := 0;

  Image1.AutoSize  := True;
end;

//=============================================================================
//  クリップボードにビットマップのデータをコピー
//  DIBとして
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  LLoadFilePath : string;
  LStream       : TMemoryStream;
  LCopyStream   : TMemoryStream;
  LhGlobal      : HGLOBAL;
  LpBuffer      : Pointer;
begin
  Image1.Picture.Assign(nil);
  ListBox1.Items.Clear;

  LLoadFilePath := 'Images\' + Trim(RadioGroup1.Items[RadioGroup1.ItemIndex]);

  LStream     := TMemoryStream.Create;
  LCopyStream := TMemoryStream.Create;
  try
    //ビットマップ画像ファイルをメモリストリームに読み込む
    LStream.LoadFromFile(LLoadFilePath);

    //ビットマップファイルヘッダ部分(先頭から40バイト)を削除したデータを作成
    LStream.Position := 0;
    LStream.Seek(SizeOf(TBitmapFileHeader), soBeginning);
    LCopyStream.CopyFrom(LStream, LStream.Size - SizeOf(TBitmapFileHeader));

    //それをクリップボードのバッファにセット
    LhGlobal := GlobalAlloc(GHND, LStream.Size);
    LpBuffer := GlobalLock(LhGlobal);
    LCopyStream.Position := 0;
    LCopyStream.ReadBuffer(LpBuffer^, LCopyStream.Size);

    Clipboard.Clear;
    //クリップボードにフォーマットを指定してセット
    Clipboard.SetAsHandle(CF_DIB, LhGlobal);
    GlobalUnlock(LhGlobal);

    Clipboard.Close;
  finally
    FreeAndNil(LStream);
    FreeAndNil(LCopyStream);
  end;
end;

//=============================================================================
//  クリップボードからヒットマップのデータを取得
//  つまり[貼り付け]の処理
//  DIBとして
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
var
  LSaveFilePath  : string;
  LStream        : TMemoryStream;
  LBmpStream     : TMemoryStream;
  LhGlobale      : THandle;
  LpBuffer       : Pointer;
  LBmpInfoHeader : TBitmapInfoHeader;
  LBmpFileHeader : TBitmapFileHeader;
  LBitmap        : TBitmap;
begin
  Image1.Picture.Assign(nil);
  LSaveFilePath := 'Images\DIB_' + Trim(RadioGroup1.Items[RadioGroup1.ItemIndex]);

  //CF_DIBのデータがある場合に処理
  if Clipboard.HasFormat(CF_DIB) then begin

    LBitmap    := TBitmap.Create;
    LStream    := TMemoryStream.Create;
    LBmpStream := TMemoryStream.Create;

    //クリップボードの指定したフォーマットのデータのポインタを取得
    LhGlobale := Clipboard.GetAsHandle(CF_DIB);
    LpBuffer  := GlobalLock(LhGlobale);
    try
      //メモリストリームにクリップボードのデータを書き込む
      LStream.WriteBuffer(LpBuffer^, GlobalSize(LhGlobale));

      //ビットマップインフォヘッダ部分を読み出す
      LStream.Position := 0;
      LStream.Read(LBmpInfoHeader, SizeOf(TBitmapInfoHeader));

      //取得した値を元にしてビットマップファイルヘッダの値をセット
      LBmpFileHeader.bfType      := $4D42;
      LBmpFileHeader.bfSize      := LStream.Size;
      LBmpFileHeader.bfReserved1 := 0;
      LBmpFileHeader.bfReserved2 := 0;
      LBmpFileHeader.bfOffBits   := SizeOf(TBitmapFileHeader);

      //クリップボードのデータの前にビットマップファイルヘッダ部を追加
      LBmpStream.Clear;
      LBmpStream.Write(LBmpFileHeader, SizeOf(TBitmapFileHeader));
      LStream.Position := 0;
      LBmpStream.CopyFrom(LStream, LStream.Size);

      //メモリストリームを保存
      LBmpStream.Position := 0;
      LBmpStream.SaveToFile(LSaveFilePath);


      //保存したファイルからビットマップ画像を読み込んで表示
      LBitmap.LoadFromFile(LSaveFilePath);
      LBitmap.AlphaFormat := afDefined;
      Image1.Transparent  := True;
      Image1.Picture.Bitmap.Assign(LBitmap);


      //ビットマップのサイズとビット深さを表示
      ListBox1.Items.Clear;
      ListBox1.Items.Add('Width  : ' + IntToStr(LBmpInfoHeader.biWidth));
      ListBox1.Items.Add('Height : ' + IntToStr(LBmpInfoHeader.biHeight));
      ListBox1.Items.Add('Colors : ' + IntToStr(LBmpInfoHeader.biBitCount) + ' bit');
    finally
      GlobalUnlock(LhGlobale);
      Clipboard.Close;

      FreeAndNil(LStream);
      FreeAndNil(LBmpStream);
      FreeAndNil(LBitmap);
    end;
  end;
end;

end.




20_フォーマット形式を定義して PNG 画像をクリップボードにコピー


[コンポーネントのアイコン作成支援プログラ] ではクリップボードの PNG 形式の画像を貼り付けることができます.イラストレータやワード,エクセル等で画像を作成して利用できます.

逆に,PNG 形式の画像としてクリップボードにセット (コピー) する機能は実装していません.PNG 形式の画像をクリップボードにセットするには,例えば以下のようなコードで可能です.
Windows の定義済みのクリップボードのフォーマット形式には PNG 形式はありません.したがって,独自に形式を定義して使用することになります.この方法は Halbow 資料館にある,任意のデータをクリップボードに受け渡す方法と同じです.コーディングの手順そのものは前項のサンプルと同じです.違うのは,フォーマットの形式を定義する部分だけです.

ワードやエクセルではフォーマット名に PNG が使われているようなので,本サンプルもそうしています.他のアプリケーションでは,このフォーマット名で検出するか,クリップボード内のデータが PNG 形式のデータであるかを調べないと利用できません.
フォーマット ID の値はフォーマット名から Windows が決めますから,常に同じ値になる保証はありません.自アプリ内だけで利用するのであればフォーマット ID の値が利用できます.



図38
サンプルの実行画面
  • 画像は添付の PNG 画像
  • これと同じ画像をディスクから読み込んでコピーする

サンプルの EXE を実行してボタンをクリックするとクリップボードに,メモリストリームに格納した PNG 画像のデータをセットするようになっています.
以下の参考リンクのサンプルプログラムを使用して,クリップボードのフォーマット形式を確認したのが下図です.PNG というフォーマット名が確認できます.



図39
クリップボード内のフォーマット形式を確認

リスト6
PNG 形式の画像をクリップボードにコピー
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ComCtrls, ExtCtrls;

type
  TForm1 = class(TForm)
    Image1: TImage;
    Button1: TButton;
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
  private
    { Private 宣言 }
    FFilePath : string;
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

uses
  Clipbrd,
  pngImage;

{$R *.dfm}

const
  FPngFormatdStr = 'PNG';

var
  FPngFormatID : Cardinal;

//=============================================================================
//  フォーム生成時の処理
//=============================================================================
procedure TForm1.FormCreate(Sender: TObject);
begin
  FFilePath := ExpandFileName('.\Images.png');

  Image1.AutoSize  := True;
  Image1.Picture.LoadFromFile(FFilePath);

  //フォーマット名からフォーマットのID値を取得(値はWindowsが決定する)
  FPngFormatID := RegisterClipboardFormat(PChar(FPngFormatdStr));
end;

//=============================================================================
//  クリップボードにPNG形式で画像をコピー
//  Windows の標準のクリップボードのフォーマットにはPNG形式はない
//  独自のフォーマット名を定義して実行する
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  LStream   : TMemoryStream;
  LhGlobale : HGLOBAL;
  LpBuffer  : Pointer;
  LPngimg   : TPngImage;
begin
  //クリップボードを空にしないとクリップボードの内容が更新されないことがある
  Clipboard.Open;
  Clipboard.Clear;

  LStream := TMemoryStream.Create;
  LPngimg := TPngImage.Create;
  try
    //Png画像のデータをメモリストリームに格納
    LPngimg.LoadFromFile(FFilePath);
    LPngimg.SaveToStream(LStream);

    //クリップボード格納用のバッファに格納
    LhGlobale := GlobalAlloc(GHND, LStream.Size);
    LpBuffer  := GlobalLock(LhGlobale);
    LStream.Position := 0;
    LStream.ReadBuffer(LpBuffer^, LStream.Size);

    //クリップボードへセット
    Clipboard.SetAsHandle(FPngFormatID, LhGlobale);
    GlobalUnlock(LhGlobale);

    Clipboard.Close;
  finally
    FreeAndNil(LStream);
    FreeAndNil(LPngimg);
  end;
end;

end.




21_PNG とビットマップの両方をクリップボードにコピー


前項のサンプルでは,PNG 形式の画像だけしかクリップボードにセットしません.
画像関係の多くのアプリケーションでは,クリップボードの CF_BITMAP, CF_DIB 形式からビットマップ画像のデータを取得しますから,これでは不便です.そこで,ビットマップ画像のデータもクリップボードにセットするようにしたのが本サンプルです.

前項のコードとの違いは,クリップボードにデータをセットするのに,Clipboard.SetAsHandle ではなく,引数の意味と型が同じである SetClipboardData 関数を使用していることです.
そして,Clipboard.Close は,SetClipboardData 関数で全ての形式のデータをセットしてから実行します.もちろん,SetClipboardData 関数の最初の引数はクリップボードのフォーマット形式ですから,データの型に応じて変更する必要があります.

Clipboard.SetAsHandle 関数は,内部で SetClipboardData 関数を実行しています.


    //クリップボードへセット
    Clipboard.SetAsHandle(FPngFormatID, LhGlobale);

     変更

    SetClipboardData(FPngFormatID, LhGlobale);



    //Closeは全ての形式のデータをSetClipboardDataした後に実行する
    Clipboard.Close;




図40
サンプルの実行画面

前項のサンプルの時と同じように,クリップボードのフォーマット形式を確認したのが下図です.PNG というフォーマット名に続いて CF_DIB 等のビットマップ形式名が確認できます.



図41
クリップボード内のフォーマット形式を確認
  • PNG 形式とビットマップ形式の両方がある
  • 順番はクリップボードにセットした順

リスト7
複数のフォーマット形式のデータをクリップボードにコピーする例
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ComCtrls, ExtCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Image1: TImage;
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
  private
    { Private 宣言 }
    FFilePath : string;
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

uses
  Clipbrd,
  pngImage;

{$R *.dfm}

const
  FPngFormatdStr = 'PNG';

var
  FPngFormatID : Cardinal;

//=============================================================================
//  フォーム生成時の処理
//=============================================================================
procedure TForm1.FormCreate(Sender: TObject);
begin
  FFilePath := ExpandFileName('.\Images.png');

  Image1.AutoSize  := True;
  Image1.Picture.LoadFromFile(FFilePath);

  FPngFormatID := RegisterClipboardFormat(PChar(FPngFormatdStr));
end;

//=============================================================================
//  複数のフォーマットのデータをクリップボードにコピー
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
  LStream   : TMemoryStream;
  LhGlobale : HGLOBAL;
  LpBuffer  : Pointer;
  LPngimg   : TPngImage;
  LBitmap   : TBitmap;
begin
  //クリップボードを空にしないとクリップボードの内容が更新されないことがある
  Clipboard.Open;
  Clipboard.Clear;

  LStream := TMemoryStream.Create;
  LPngimg := TPngImage.Create;
  LBitmap := TBitmap.Create;
  try
    //-----------------------------------------------------
    //  TPngImageをクリップボードにコピーするコード
    //-----------------------------------------------------

    //Png画像のデータをメモリストリームに格納
    LPngimg.LoadFromFile(FFilePath);
    LPngimg.SaveToStream(LStream);

    //クリップボード格納用のバッファに格納
    LhGlobale := GlobalAlloc(GHND, LStream.Size);
    LpBuffer  := GlobalLock(LhGlobale);
    LStream.Position := 0;
    LStream.ReadBuffer(LpBuffer^, LStream.Size);

    //クリップボードへセット
    SetClipboardData(FPngFormatID, LhGlobale);
    GlobalUnlock(LhGlobale);


    //-----------------------------------------------------
    //  以下,TBitmapをクリップボードにコピーするコード
    //-----------------------------------------------------

    //Png画像からTBitmap生成してメモリストリームに格納
    LBitmap.Assign(LPngimg);
    LStream.Clear;
    LBitmap.SaveToStream(LStream);

    //クリップボード格納用のバッファに格納
    LhGlobale := GlobalAlloc(GHND, LStream.Size);
    LpBuffer  := GlobalLock(LhGlobale);
    LStream.Position := 0;
    LStream.ReadBuffer(LpBuffer^, LStream.Size);

    //クリップボードへセット
    //このコードの場合はCF_BITMAP,CF_DIBは同じとなる
    SetClipboardData(CF_DIB, LhGlobale);
    GlobalUnlock(LhGlobale);


    //Close
    Clipboard.Close;
  finally
    FreeAndNil(LStream);
    FreeAndNil(LPngimg);
    FreeAndNil(LBitmap);
  end;
end;

end.




22_SaveToClipboardFormat メソッドを使用したコピー


Delphi には TBitmap.SaveToClipboardFormat, TBitmap.LoadFromClipboardFormat 等,クリップボードへのコピー,クリップボードからのデータ取得用の便利なメソッドが実装されています.

下に示したコードは TPngImage.SaveToClipboardFormat メソッドを使用する例です.このメソッドを使用するとクリップボードへのコピーが簡単なコードで実現できますが,このメソッドは TPngImage をアルファチャンネルなしのビットマップとしてコピーします.透明色は「白」となります.
また,TBitmap.SaveToClipboardFormat メソッドは CF_BITMAP 形式でのコピーとなります.上のサンプルで示したように,アルファチャンネルの情報を保持したままでクリップボードにデータをセットすることはできません.



リスト8
TPngImage.SaveToClipboardFormat メソッドを使用したクリップボードへのコピー
CF_BITMAP 形式でのコピーとなる
procedure TForm1.Button1Click(Sender: TObject);
var
  LPngimg  : TPngImage;
  LFormat  : Word;
  LData    : THandle;
  LPalette : HPALETTE;
begin
  Clipboard.Open;
  Clipboard.Clear;

  LPngimg := TPngImage.Create;
  try
    //Png画像を読み込む
    LPngimg.LoadFromFile(FFilePath);
    //クリップボードにコピーするために必要なデータを取得
    LPngimg.SaveToClipboardFormat(LFormat, LData, LPalette);
    //クリップボードへセット
    Clipboard.SetAsHandle(LFormat, LData);

    Clipboard.Close;
  finally
    FreeAndNil(LPngimg);
  end;
end;




23_Delphi 6 や Delphi 7 に付属のイメージエディタについて


旧い Delphi にはコンポーネントのアイコン画像や Glyph 用ビットマップ等を作成するための画像編集ソフトとしてイメージエディタ (Image Editor - imagedit.exe) が付属していました. 下図がそのイメージエディタで,Delpi 6 Pro 版に付属しているイメージエディタです.

Glyph 用のビットマップが作成できるとは言っても,実際には必要な幅と高さのビットマップを新規に作成するものです.下図は 48 x 24 の 256 色のビットマップの新規作成画面です.
ビットマップは最大 256 色が設定できますが,コンポーネントのアイコン用ビットマップと ICO 形式は 16 色までしか使用できません.マウスカーソル作成で使用可能なのは 4 色だけです.

現在アイコン集として入手可能な画像の多くはフルカラー,あるいはアルファチャンネル付きの 32 ビットの PNG 形式の画像です.このイメージエディタでは PNG 形式の画像は読み込めません.また,他の形式の画像であっても,16 色または 256 色に減色しなければ読み込めません.このイメージエディタを使用して画像を作成したり編集するのは無理があると言えるでしょう.
しかしながら,BDE もこのイメージエディタも大きな役割を果たしたことは言うまでもありません.



図42
Delphi 6 Pro に付属のイメージエディタ (Image Editor)
  • 右下は画像のサイズと色数の設定用ダイアログ (最大 256 色)
  • このダイアログは合成画像.実際には新規作成時だけ表示される