Delphi6 Personal,Windows2000の環境です。
TBitMapの一部の色をTBitmap.ScanLineを使用して、別の色に置き換えようとしています
。
現在、目的は達成しましたが、今ひとつ仕組みが良くわからないので質問させて頂きます。
私は、グラフィック関係を扱うのは、これが初めてですので、用語等、不適切かもしれま
せんがよろしくお願いします。
TBitmap.ScanLineへのアクセス方法としては、
ヘルプのTBitmap.ScanLineの例において、PByteArrayへ" P[x] := y "というように直接
カラー値を指定する方法(以下 TColor直接方式)と
http://madia.world.coocan.jp/delphi/Win32API/getcolorcount.htmのように
TBitmap.ScanLineに対して、入力された値をG,R,Bの各要素に分解して指定する(ポインタ
型配列は不要)方法(以下 RGB変換方式)
の二つがあるようで、私が調べたところでは、後者の方法で処理されているものばかりの
ようです。
調べている過程で、PixelFormatとScanLineへの割り当てのポインタ型配列のサイズの組
合せで色々な結果になることを知りましたが、いまいち、仕組みが理解できません。いく
つかの結果について説明していただけるとありがたいです。
1.TColor直接方式、(PixelFormatサイズ < ポインタ型配列のサイズ)で縞模様
ex. pf1bit & PByteArray
2.TColor直接方式、(PixelFormatサイズ > ポインタ型配列のサイズ)で描画領域が半分や
1/4?になったりする。
ex. pf24bit & PByteArray
3.TColor直接方式、(PixelFormatサイズ = ポインタ型配列のサイズ)で一色のベタ塗りと
なりますが、色はやはり違います。pf32bit & PIntegerArrayでは、16進数表示でのR,Bの
数値が逆になっているようです。その他の組合せの場合には、入力値と結果のカラー値の
関連性は良くわかりません。
4.RGB変換方式のpf24bit方式のみが正しく描画できるのは、TRGBColorの設定と関連があ
りそうですが、他のPixelFormatで正しく描画するためのTRGBColorの設定とは?
5.RGB変換方式で、PixelFormatがpf16bit以下では、画像の下方の模様が変化している。
ex. pf1bitでは特に顕著
6.RGB変換方式で、pf32bitでは描画が3/4程度になる(数字的にはありそうですが..)。
で、こういったことを調べるための簡単なツールを作りましたので、それを次のスレに掲
載します。
ツール作成手順
1.ファイル>新規作成>アプリケーション
2.Form1にTButton(2つ)、TEdit(1つ)、TLabel(5つ)、TPanel(6つ)、TComboBox(2つ)、
TTimer(1つ)を載せる。この際、TPanel内に他のコンポーネントが入ってしまわないように気をつける
3.Unit1.pasを以下のコードですべて置き換える
4.Form1のOnCreateイベントをダブルクリック
5.コンパイルで完成
〜 Unit1.pas 置き換えコード 〜
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
Edit1: TEdit;
Label1: TLabel;
Label2: TLabel;
Panel1: TPanel;
Panel2: TPanel;
Panel3: TPanel;
Panel4: TPanel;
Panel5: TPanel;
Panel6: TPanel;
Timer1: TTimer;
ComboBox1: TComboBox;
ComboBox2: TComboBox;
Label3: TLabel;
Label4: TLabel;
Label5: TLabel;
procedure Button1Click(Sender: TObject);
procedure Timer1Timer(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
{ Private 宣言 }
public
{ Public 宣言 }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
var
clIndex:TColor;
x,y:Integer;
BitMap:TBitMap;
PB:PByteArray;
PW:PWordArray;
PI:PIntegerArray;
TPF:TPixelFormat;
begin
BitMap:=TBitMap.create;
if Edit1.Text='' then Exit;
if ComboBox1.ItemIndex=0 then begin
ShowMessage('PixelFormatを選択してください');
Exit;
end;
if ComboBox2.ItemIndex=0 then begin
ShowMessage('ポインタ配列を選択してください');
Exit;
end;
//カラー値入力
try
clIndex:=StrToInt(Edit1.Text);
Panel5.Caption:='10進数 = '+Edit1.Text;
Panel6.Caption:='16進数 = '+Edit1.Text;
if Edit1.Text[1]<>'$' then
Panel6.Caption:='16進数 = $'+IntToHex(clIndex,8)
else
Panel5.Caption:='10進数 = '+IntToStr(clIndex);
except
end;
BitMap.Width:=200;
BitMap.Height:=100;
TPF:=TPixelFormat(ComboBox1.ItemIndex);
BitMap.PixelFormat:=TPF;
try
try
for y:=0 to BitMap.Height -1 do begin
case ComboBox2.ItemIndex of
1:begin
PB:=BitMap.ScanLine[y];
for x:=0 to BitMap.Width -1 do PB[x]:=clIndex;
end;
2:begin
PW:=BitMap.ScanLine[y];
for x:=0 to BitMap.Width -1 do PW[x]:=clIndex;
end;
3:begin
PI:=BitMap.ScanLine[y];
for x:=0 to BitMap.Width -1 do PI[x]:=clIndex;
end;
end;
end;
Canvas.Draw(0,0,BitMap);
SetCursorPos(Left+BitMap.Width div 2,Top+(Height-ClientHeight)+BitMap.Height div 2);
except
ShowMessage('現在のPixcelFormat、ポインタ型配列、カラー値の組合せは有効ではありません');
end;
finally
BitMap.Free;
end;
Timer1Timer(Sender);
//色の一致判定
if Panel5.Caption=Panel2.Caption then Label5.Caption:='○' else Label5.Caption:='×';
Edit1.Text:='';
end;
procedure TForm1.Timer1Timer(Sender: TObject);
var
R,G,B:Integer;
DeskDC:HWND;
pMs:Tpoint;
clPoint:TColor;
begin
//カーソル位置取得
GetCursorPos(pMs);
Panel1.Caption:='x ='+IntToStr(pMs.x)+', y ='+IntToStr(pMs.y);
//デスクトップDC(デバイスコンテキスト)取得
DeskDC:=GetDC(0);
//カーソル位置カラー(10進数)取得
clPoint:=GetPixel(DeskDC,pMs.x,pMs.y);
Panel2.Caption:='10進数 = '+IntToStr(clPoint);
//DC(デバイスコンテキスト)解放
ReleaseDC(0,DeskDC);
//カーソル位置カラー(16進数)取得
Panel3.Caption:='16進数 = $'+IntToHex(clPoint,8);
//カーソル位置カラー(RGB)取得
R:=GetRValue(clPoint);
G:=GetGValue(clPoint);
B:=GetBValue(clPoint);
Panel4.Caption:='(R,G,B) ='+'('+IntToStr(R)+', '+IntToStr(G)+' ,'+IntToStr(B)+')';
end;
procedure TForm1.Button2Click(Sender: TObject);
type
PRGBColor=^TRGBColor;
TRGBColor=array[0..32768-1] of TRGBTriple;
var
clIndex,x,y:Integer;
BitMap:TBitmap;
P:PRGBColor;
TPF:TPixelFormat;
begin
BitMap:=TBitMap.create;
if Edit1.Text='' then Exit;
if ComboBox1.ItemIndex=0 then begin
ShowMessage('PixelFormatを選択してください');
Exit;
end;
//カラー値入力
try
clIndex:=StrToInt(Edit1.Text);
Panel5.Caption:='10進数 = '+Edit1.Text;
Panel6.Caption:='16進数 = '+Edit1.Text;
if Edit1.Text[1]<>'$' then
Panel6.Caption:='16進数 = $'+IntToHex(clIndex,8)
else
Panel5.Caption:='10進数 = '+IntToStr(clIndex);
except
end;
BitMap.Width:=200;
BitMap.Height:=100;
TPF:=TPixelFormat(ComboBox1.ItemIndex);
BitMap.PixelFormat:=TPF;
try
for y:=0 to BitMap.Height -1 do begin
P:=BitMap.ScanLine[y];
for x:=0 to BitMap.Width -1 do begin
P[x].rgbtRed:=GetRValue(clIndex);
P[x].rgbtGreen:=GetGValue(clIndex);
P[x].rgbtBlue:=GetBValue(clIndex);
end;
Canvas.Draw(0,0,BitMap);
SetCursorPos(Left+BitMap.Width div 2,Top+(Height-ClientHeight)+BitMap.Height div 2);
end;
finally
BitMap.Free;
end;
Timer1Timer(Sender);
//色の一致判定
if Panel5.Caption=Panel2.Caption then Label5.Caption:='○' else Label5.Caption:='×';
Edit1.Text:='';
end;
procedure TForm1.FormCreate(Sender: TObject);
var
i:Integer;
com:TComponent;
slList:TStringList;
begin
//フォームサイズ変更
Width:=480;
Height:=330;
//ラベル設定
for i:=1 to 5 do begin
com:=FindComponent('Label'+IntToStr(i));
with (com as TLabel) do begin
Left:=220;
case i of
1:begin
Caption:='現在のカーソル位置は...';
Top:=155;
end;
2:begin
Caption:='現在のマウスカーソル位置カラーは...';
Top:=205;
end;
3:begin
Caption:='描画指定のカラーは...';
Top:=75;
end;
4:begin
Caption:='描画させたいカラー入力';
Top:=35;
end;
5:begin
Caption:='';
Top:=170;
Left:=65;
Font.Size:=60;
end;
end;
end;
end;
//パネル設定
for i:=1 to 6 do begin
com:=FindComponent('Panel'+IntToStr(i));
with (com as TPanel) do begin
Caption:='';
Left:=220;
BevelOuter:=bvLowered;
BevelWidth:=2;
Alignment:=taLeftJustify;
Width:=160;
Height:=20;
case i of
1:Top:=170;
2:Top:=220;
3:Top:=245;
4:Top:=270;
5:Top:=90;
6:Top:=115;
end;
end;
end;
//ボタン設定
for i:=1 to 2 do begin
com:=FindComponent('Button'+IntToStr(i));
with (com as TButton) do begin
Caption:='';
Left:=350;
Width:=100;
Height:=25;
case i of
1:begin
Caption:='TColor直接方式';
Top:=32;
OnClick:=Button1Click;
end;
2:begin
Caption:='RGB変換方式';
Top:=60;
OnClick:=Button2Click;
end;
end;
end;
end;
//Edit1設定
with Edit1 do begin
Edit1.Text:='';
Left:=220;
Top:=50;
end;
//コンボボックス設定
for i:=1 to 2 do begin
com:=FindComponent('ComboBox'+IntToStr(i));
with (com as TComboBox) do begin
Top:=5;
Width:=100;
Height:=20;
slList:=TStringList.Create;
case i of
1:begin
Left:=220;
slList.Add('PixcelFormat');
slList.Add('pf1bit');
slList.Add('pf4bit');
slList.Add('pf8bit');
slList.Add('pf15bit');
slList.Add('pf16bit');
slList.Add('pf24bit');
slList.Add('pf32bit');
end;
2:begin
Left:=350;
slList.Add('ポインタ型配列');
slList.Add('PByteArray');
slList.Add('PWordArray');
slList.Add('PIntegerArray');
end;
end;
Items:=slList;
ItemIndex:=0;
slList.Free;
end;
end;
//Timer設定
with Timer1 do begin
Enabled:=True;
Interval:=100;
OnTimer:=Timer1Timer;
end;
end;
end.
うーむ、pixelformat の違いによる内部色データの形式がわかってないだけでは?
ただそれだけのような気がします。ScanLine の各ピクセルの色データに TColor の
色データを直接設定する、と言う例はきいた事がありません。
各 PixelFormat に対応した ScanLine にアクセスするための
ラッパークラスをつくったことがあります。内部色データを
調べる参考になるでしょう。
http://junki.lix.jp/delphigr.html
junkiさん、ありがとうございます。
>pixelformat の違いによる内部色データの形式がわかってないだけでは
http://www.geocities.co.jp/Playtown-Knight/6845/sd_doc/format_windib.html#SECT6
とかを読んで、ScanLine の各ピクセルの色データにTColorの
色データを直接設定するのではなさそうだということは理解できました。
まだ、具体的な理解には遠いですが、junkiさんの
http://junki.lix.jp/delphigr/033TBmpData1.htm
のような感じで理解していけそうな感じです。
ありがとうございました。
ツイート | ![]() |