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 をきれいに印刷する

最終更新: 8012 日前

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  D1   D2   D3   D4   D5   D6   D7   3.1   95   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

Tips
Delphi
Home
Osamu Takeuchi osamu@big.or.jp

.