Delphi Tips
>> Index
● 05/17 文字列や画像データをリソースに埋め込むためのコンポーネント
● 06/01 色表現について(RGB, HSV, YUV など)
● 09/21 Delphi4 で TBitmap を pf1bit で使うときの注意点(不具合回避)
● 09/09 Metafile が Draw で1ピクセル小さく描画される
● 02/11 Bitmap のパレットに使いたい色を追加する
● 02/08 TColor を RGB 値へ変換する
● 02/08 メタファイルを wmf 形式でコピーするときの注意
● 02/08 Glyphに張ったビットマップの背景がおかしくなる
● 02/08 中村さんありがとうシリーズ:ビットマップ・パレット編
● 02/08 TBitmap の Width/Height に 0 を代入すると例外が発生する
● 02/08 Bitmap から Icon を作る
● 02/08 TBitmap をきれいに印刷する
最終更新: 8227 日前
0320 D1 D2 D3 D4 D5 D6 D7 3.1 95 98 作成: 2002/05/17 osamu rev 1.1 B1 B3 B4 B5 B6 B7 NT3 NT4 2K XP 更新: 2002/05/17 osamu 編集
文字列や画像データをリソースに埋め込むためのコンポーネント
プログラム内部で使いたい文字列や画像のデータを、フォーム上に置いた非ビジュアルコンポーネントに保存しておくと、アプリケーションと別にファイルを配布する必要が無くなり、便利な場合があります。
そういった用途に使えるコードが[Delphi-ML:67285]のスレッドに紹介されています。ただし、画像データなどは文字列にエンコードされますので、そのままファイルを持つ場合に比べ、ファイルサイズは大きくなってしまいます。
[Delphi-ML:50664]で中村さんが紹介されたコンポーネントは任意のバイナリデータを内部に持てるようです。
参照: [Delphi-ML:67285] <文字列> <PASCAL>
0303 D1 D2 D3 D4 D5 D6 D7 3.1 95 98 作成: 2000/06/01 osamu rev 1.1 B1 B3 B4 B5 B6 B7 NT3 NT4 2K XP 更新: 2000/06/01 osamu 編集
色表現について(RGB, HSV, YUV など)
色を数値で表現する有名な方法として、RGB, HSV, YUV などがありますが、このような色表現同士の相互変換およびこれらを用いた画像処理に関してよくまとめてあるページを紹介します。
カラーのお話 -詳細- :
http://robotics.me.es.osaka-u.ac.jp/~koji/html/color_detail.html
参照:
0270 D1D2 D3 D4 D5 D6 D7 3.195 98 作成: 1999/09/21 osamu rev 1.1 B1 B3 B4 B5 B6 B7 NT3 NT4 2K XP 更新: 1999/09/21 osamu 編集
Delphi4 で TBitmap を pf1bit で使うときの注意点(不具合回避)
TBitmap は pf1bit で Width/Height が共に 0 以上になると 1bpp DIB を作成しますが、2色のカラーテーブルを初期化していません。
さらに、Width/Height が 0 以上の TBitmap を PixelFormat で pf1bit へ形式変換する場合
DDB -> 1bpp DIB 変換なら 黒白2色のカラーテーブルが作られます。 -> OK
DIB -> 1bpp DIB 変換なら 古いカラーテーブルが引き継がれます。 -> バグ
となります。
結局、PixelFormat := pf1bit; がまともに動くのは、古い PixelFormat の値が pfDevice で Width > 0, Height > 0 の場合だけです。たとえば,以下のようなコードで問題が発生します。
Bitmap1 := TBitmap.Create; // スクリーン互換 DDB を作成
Bitmap1.PixelFormat := pf1bit; // Size がゼロのまま 1bit DIB に変換
Bitmap1.Width := 1000;
Bitmap1.Height := 1000;
これを、
Bitmap1 := TBitmap.Create; // スクリーン互換 DDB を作成
Bitmap1.Width := 1000;
Bitmap1.Height := 1000;
Bitmap1.PixelFormat := pf1bit; // Size を設定してから 1bit DIB に変換
とすれば、正常に動きます。ただし、一旦ばかでかい DDB ができてしまうので,リソースの消費が問題になります。この場合には、以下のようにするのがベストでしょう。
Bitmap1 := TBitmap.Create; // スクリーン互換 DDB を作成
Bitmap1.Width := 1;
Bitmap1.Height := 1;
Bitmap1.PixelFormat := pf1bit; // 小さな Size を設定してから 1bit DIB に変換
Bitmap1.Width := 1000;
Bitmap1.Height := 1000; // 大きくする
基礎知識:
TBitmap.Monochrome=True; は 1bit DDB
TBitmap.PixelFormat:=pf1bit; は 1bit DIB
を作成します。
この辺は、Delphi Magazine 3/4/5号で中村@NECさんが詳しく説明して下さっています。
参照: [Delphi-ML:42732] <バグ>
0248 D1 D2 D3 D4 D5 D6 D7 3.1 95 98 作成: 1999/09/09 osamu rev 1.1 B1 B3 B4 B5 B6 B7 NT3 NT4 2K XP 更新: 1999/09/09 osamu 編集
Metafile が Draw で1ピクセル小さく描画される
>拡張メタファイルを作成するツールを作ろうとしています。
>そこで、メタファイルに編集を加えるたびに以前編集した像が
>1ドット(?)ずつ縮小してしまう問題があるのです。
TMetafile.Draw を見ると
R := Rect;
Dec(R.Right); // Metafile rect includes right and bottom coords
Dec(R.Bottom);
PlayEnhMetaFile(ACanvas.Handle, FImage.FHandle, R);
となっていて、描画先矩形を 1ドット分縮小しているのが原因のようです。
Win32 Programmer's Ref. で PlayEnhMetafile を見ると、
Points along the edges of the rectangle are included in the picture.
なんて微妙なことが書いてあるのですが、実際には Win98 で試してみた限り矩形領域を小さくするのは正しくないようです。Dec をコメントにすると完全に同じ大きさの図形が得られます。
対処としては graphics.pas を修正するか、Right, Bottom を一つ大きめに指定して StretchDraw するしかないようです。
ただ、ディスプレイデバイスとメタファイルの参照デバイスが異なると多少の誤差は避けられないようです。この辺を考慮して高精度のメタファイルを作るにはメタファイルを直接編集するしかないと思います。
参照: [Delphi-ML:33593] <バグ> <描画>
0138 D1 D2 D3 D4 D5 D6 D7 3.1 95 98 作成: 1999/02/11 osamu rev 1.1 B1 B3 B4 B5 B6 B7 NT3 NT4 2K XP 更新: 1999/02/11 osamu 編集
Bitmap のパレットに使いたい色を追加する
>どうやれば どんなBMP にでも 画像を悪化 せずに
>自分で指定した色で文字を描画出来るようになるのでしょうか
取りあえず、こんな処理はどうでしょう?
var bm: TBitmap;
pal: TMaxLogPalette;
PalSize: WORD;
i: Integer;
const Colors: array[0..15] of TColor =
(clBlack, clMaroon, clGreen, clOlive,
clNavy, clPurple, clTeal, clSilver,
clGray, clRed, clLime, clYellow,
clBlue, clFuchsia, clAqua, clWhite); // VGA Colors
:
:
bm := TBitmap.Create;
bm.LoadFromFile('c:\windows\雲.bmp');
// パレットエントリ数を得る
GetObject(bm.Palette, 2, @PalSize);
// パレットの色を取得
GetPaletteEntries(bm.Palette, 0, PalSize-1, pal.palPalEntry);
// パレットのエントリを16色分ずらす
for i := PalSize-1 + 16 downto 16 do
if i < 256 then
pal.palPalEntry[i] := pal.palPalEntry[i-16];
// ずらして空いた部分に VGA カラーを埋め込む
for i := 0 to 15 do begin
pal.palPalEntry[i].peRed := GetRValue(Colors[i]);
pal.palPalEntry[i].peGreen := GetGValue(Colors[i]);
pal.palPalEntry[i].peBlue := GetBValue(Colors[i]);
pal.palPalEntry[i].peFlags := 0;
end;
if Palsize + 16 > 256 then
pal.palNumEntries := 256
else
pal.palNumEntries := PalSize + 16;
pal.palVersion := $0300;
// VGA カラーを足したパレットをビットマップにセット
// TBitmap は新しいパレットで色の劣化が最小限に
// なるように自動的にカラーマッチをやり直してくれます。
bm.Palette := CreatePalette(PLogPalette(@pal)^);
これで VGA Color が描けるビットマップになると思います。
ほとんど色は劣化しません。ただ、パレットの後半に重要な色が有ると多少劣化するかも。そこまでやるには VGA Color を挿入する前にパレットの色を明るさの降順に並べ替える処理を入れた方がいいと思います。
また、VGA Colors と同色の色が有った場合、その色を挿入しないようにすれば、より品質が向上すると思います。
参照: [Delphi-ML:24045] <その他Windows関連> <Windows>
0116 D1 D2 D3 D4 D5 D6 D7 3.1 95 98 作成: 1999/02/08 osamu rev 1.1 B1 B3 B4 B5 B6 B7 NT3 NT4 2K XP 更新: 1999/02/08 osamu 編集
TColor を RGB 値へ変換する
下のような関数を作ればよいです。
procedure ColorToRGB(c: TColor; var r,g,b: Byte);
var IntColor: Integer;
begin
IntColor:= ColorToRGB(c);
r:= GetRValue(IntColor);
g:= GetGValue(IntColor);
b:= GetBValue(IntColor);
end;
参照: [builder:6369]
0130 D1 D2 D3 D4 D5 D6 D7 3.1 95 98 作成: 1999/02/08 osamu rev 1.1 B1 B3 B4 B5 B6 B7 NT3 NT4 2K XP 更新: 1999/02/08 osamu 編集
メタファイルを wmf 形式でコピーするときの注意
Word 95 などのように旧メタファイル形式にしか対応しないアプリにメタファイルをコピーするときの注意点です。
Windows はクリップボードにエンハンストメタファイルが有って CF_METAFILEPICT 形式のメタファイルを要求されるとメタファイルを自動的に変換(emf->wmf)します。
ところが Windows がメタファイルをエンハンストから旧メタファイルに変換するとき境界枠の大きさやアスペクト比が失われてしまいます。
以下のように、はじめから wmf でクリップボードにコピーしておくといいようです。
procedure SaveToClipAsWMF(mf: TMetafile);
var
hMetafilePict: THandle;
pMFPict: PMetafilePict;
DC: THandle;
Length: Integer;
Bits: Pointer;
h: HMETAFILE;
begin
DC := GetDC(0);
try
Length := GetWinMetaFileBits(mf.Handle, 0, nil,
MM_ANISOTROPIC, DC);
Assert(Length > 0);
GetMem(Bits, Length);
try
GetWinMetaFileBits(mf.Handle, Length, Bits,
MM_ANISOTROPIC, DC);
h := SetMetafileBitsEx(Length, Bits);
Assert(h <> 0);
try
hMetafilePict := GlobalAlloc(GMEM_MOVEABLE or
GMEM_DDESHARE,
Length);
Assert(hMetafilePict <> 0);
try
pMFPict := GlobalLock(hMetafilePict);
pMFPict^.mm := MM_ANISOTROPIC;
pMFPict^.xExt := mf.Width;
pMfPict^.yExt := mf.Height;
pMfPict^.hMF := h;
GlobalUnlock(hMetafilePict);
Clipboard.SetAsHandle(CF_METAFILEPICT, hMetafilePict);
except
GlobalFree(hMetafilePict);
raise;
end;
except
DeleteObject(h);
raise;
end;
finally
FreeMem(Bits);
end;
finally
ReleaseDC(0, DC);
end;
end;
参照: [Delphi-ML:23065] <その他Windows関連> <Windows>
0049 D1 D2 D3 D4 D5 D6 D7 3.1 95 98 作成: 1999/02/08 osamu rev 1.1 B1 B3 B4 B5 B6 B7 NT3 NT4 2K XP 更新: 1999/02/08 osamu 編集
Glyphに張ったビットマップの背景がおかしくなる
Glyphでは、左下隅のピクセルの色を透過色として扱うので、背景となる色をちゃんと表示するには、ビットマップを一回り大きく作って表示したい絵の中に使われていない色で「縁」を作ってやればよいです。
参照: [Delphi-ML:6213] <バグ>
0050 D1 D2 D3 D4 D5 D6 D7 3.1 95 98 作成: 1999/02/08 osamu rev 1.1 B1 B3 B4 B5 B6 B7 NT3 NT4 2K XP 更新: 1999/02/08 osamu 編集
中村さんありがとうシリーズ:ビットマップ・パレット編
ビットマップやパレットについて分からないとき、中村さんのホームページ、
http://www.asahi-net.or.jp/~HA3T-NKMR/
を見に行くのは当然として、Delphi-MLでの中村さんの発言をまとめてみましたので、こちらもご利用ください。
[Delphi-ML:01572] Re: Palette
[Delphi-ML:01690] Re: How To SystemColor ?
[Delphi-ML:01865] Re: How to Use Palette ???
[Delphi-ML:01969] Re: About TMediaPlayer and TImage
[Delphi-ML:02075] The Bug of FreeMem
[Delphi-ML:02365] Re: Palette 98とATで機種依存?
[Delphi-ML:03293] How Does Delphi Copy Palette?
[Delphi-ML:03376] Re: 16-Color Palette Bitmap
[Delphi-ML:04017] Re: BITMAPの色がまともに出ない
[Delphi-ML:04344] Re: [Q]:Strech Image Save ToFile
[Delphi-ML:04494] Re: クリップボードからの画像貼付けについて
[Delphi-ML:05140] Re: Help! Bitmap Handle to Address
[Delphi-ML:05271] Re: 256 color Bitmap を作りたい
[Delphi-ML:05312] Re: 256 color Bitmap
[Delphi-ML:05343] Re: 256 color Bitmap
[Delphi-ML:05711] Re: パレットの合成
[Delphi-ML:05343] Re: FloodFill
[Delphi-ML:06583] Re: rectangleについて(Canvasの秘密)
[Delphi-ML:06587] Re: rectangleについて(Canvasの秘密)
[Delphi-ML:07096] Re: モノクロビットマップについて
[Delphi-ML:07199] Re: クリップボード経由でグラフィックを印刷する方法?
[Delphi-ML:08388] Re: Delphi3がやってきた。
[Delphi-ML:08518] Re: チョー初歩的、スプライト
[Delphi-ML:08810] Re: パレット破壊?
[Delphi-ML:10676] Re: ビットマップをだんだん暗くしたい
[Delphi-ML:13018] Re: ScanLineの使用方法?
[Delphi-ML:13230] The Oracle of Delphi
[Delphi-ML:14252] Re: はじめまして&質問です
[Delphi-ML:14915] Re: TBitmapで DIBのビット値へのポインタを得る方法
[Delphi-ML:15271] Re: RE: Re: グラフィックの扱いについて
現在まだまだ増加中
近々、中村さんありがとうシリーズ:TImage編、Printer編なども追加していくつもりです。
参照:
0058 D1 D2 D3 D4 D5 D6 D7 3.1 95 98 作成: 1999/02/08 osamu rev 1.1 B1 B3 B4 B5 B6 B7 NT3 NT4 2K XP 更新: 1999/02/08 osamu 編集
TBitmap の Width/Height に 0 を代入すると例外が発生する
TBitmap のバグか仕様か以下のようなコードで例外が発生する。
void __fastcall TClass1::Method1( void )
{
Graphics::TBitmap *Bmp;
Bmp = new Graphics::TBitmap();
Bmp->LoadFromFile( "BMPファイル名" );
Bmp->Width = 0; // <-ここでEOutOfResource例外が発生
delete Bmp;
}
このコードは BCB1 では問題なかったが BCB3 では例外が発生する。
内部ビットマップ形式が DDB から DIB に変わったことが関連している。
Bmp->Width = 0;
の前に、
Bmp->ReleaseHandle();
とすることで回避が可能。
参照: [builder:4889] <バグ>
0059 D1 D2 D3 D4 D5 D6 D7 3.1 95 98 作成: 1999/02/08 osamu rev 1.1 B1 B3 B4 B5 B6 B7 NT3 NT4 2K XP 更新: 1999/02/08 osamu 編集
Bitmap から Icon を作る
Windows 標準の 16 色パレットを使った BMP から 16 色アイコンを作る方法が、[Delphi-ML:19514] に紹介されている。
参照: [Delphi-ML:19514]
0092 D1 D2 D3 D4 D5 D6 D7 3.1 95 98 作成: 1999/02/08 osamu rev 1.1 B1 B3 B4 B5 B6 B7 NT3 NT4 2K XP 更新: 1999/02/08 osamu 編集
TBitmap をきれいに印刷する
TBitmap 印刷用手続きの中村@NECさんバージョンです。
StretchDIBits を使うところがミソだそうです。
procedure StretchDrawBitmap(Canvas: TCanvas; // 描画先キャンバス
r: TRect; // 描画先の範囲
Bitmap: TBitmap // ビットマップ
);
var OldMode: Integer; // StretchMode のセーブ
Info: PBitmapInfo; // DIB ヘッダ + カラーテーブル
InfoSize: Integer; // DIB ヘッダ + カラーテーブル
Image: Pointer; // DIB のピクセルデータ
ImageSize: Integer; // DIB のピクセルデータのサイズ。
begin
// DIB の「ヘッダ+カラーテーブル」の大きさと ピクセル
// データの大きさを求める
GetDIBSizes(Bitmap.Handle, InfoSize, ImageSize);
Info := Nil;
Image := Nil;
try
// DIB 用のメモリーを確保
Info := AllocMem(InfoSize);
Image := Allocmem(ImageSize);
// DIB を取り出す
GetDIB(Bitmap.Handle, Bitmap.Palette, Info^, Image^);
// 描画!!
OldMode := SetStretchBltMode(Canvas.Handle, COLORONCOLOR);
StretchDIBits(Canvas.Handle,
r.Left, r.Top,
r.Right - r.Left, r.Bottom - r.Top,
0, 0, Info^.bmiHeader.biWidth,
Info^.bmiHeader.biHeight,
Image, Info^, DIB_RGB_COLORS, SRCCOPY);
SetStretchBltMode(Canvas.Handle, OldMode);
finally
if Info <> Nil then FreeMem(Info);
if Image <> Nil then FreeMem(Image);
end;
end;
参照: [Delphi-ML:20572] <印刷>
[新規作成] [最新の情報に更新]
How To
Lounge
KeyWords
Osamu Takeuchi osamu@big.or.jp
Tips
Delphi
Home