///////////////////////////////////////////////////////////////////// 槻 誠三(けやき せいぞう)です。 いつもお世話になっています。 基本的な質問、並びに長文で大変恐縮です。 Bitmap 形式の画像の明るさを補正する場合に例えば、Canvas.Pixels を使って procedure TForm1.BrightP(Bitmap: TBitmap; Ratio: Integer); var x, y: Integer; Pixel: Integer; R, G, B: Integer; begin if (Ratio < 0) or (Ratio > 200) then // 変更する明るさの % 値 Exit; // 0 % 〜 200 % for y := 0 to Bitmap.Height - 1 do begin for x := 0 to Bitmap.Width - 1 do begin Pixel := TColor(Bitmap.Canvas.Pixels[x][y]); R := Pixel and $000000FF; // Red G := (Pixel and $0000FF00) shr 8; // Green B := (Pixel and $00FF0000) shr 16; // Blue R := R * Ratio div 100 if R > 255 then R := 255 else if R < 0 then R := 0; G := G * Ratio div 100 if G > 255 then G := 255 else if G < 0 then G := 0; B := B * Ratio div 100 if B > 255 then B := 255 else if B < 0 then B := 0; Pixel := R or (G shl 8) or (B shl 16); Bitmap.Canvas.Pixels[x][y] = TColor(Pixel); end; end; end; のようにやると大変時間がかかるので、ScanLine を使おうと思って 次の様なコードを書いてみました。 procedure TForm1.BrightS(Bitmap: TBitmap; Ratio: Integer); var x, y: Integer; R, G, B: Integer; P : PByteArray; begin if (Ratio < 0) or (Ratio > 200) then // 変更する明るさの % 値 Exit; // 0 % 〜 200 % for y := 0 to Bitmap.Height - 1 do begin P := Bitmap.ScanLine[y]; for x := 0 to Bitmap.Width - 1 do begin R := P[x * 3]; // Red G := P[x * 3 + 1]; // Green B := P[x * 3 + 2]; // Blue R := R * Ratio div 100 if R > 255 then R := 255 else if R < 0 then R := 0; G := G * Ratio div 100 if G > 255 then G := 255 else if G < 0 then G := 0; B := B * Ratio div 100 if B > 255 then B := 255 else if B < 0 then B := 0; P[x * 3] := R; // Red P[x * 3 + 1] := G; // Green P[x * 3 + 2] := B; // Blue end; end; end; ところが、この BrightS 手続きは、Bitmap.PixelFormat = pf24bit の とき、すなわち 24 ビットカラーを前提としたコードです。 PixelFormat が他の値の時の対処のしかたが分かりません。 たとえば、pf8bit 256色カラーのときなんかはそもそも、Red, Green, Blue の 3 要素に分ける事が可能なんでしょうか。また逆に pf32bit の場合は、 最上位の 8 ビットは何に使われているんでしょうか。 どなたかお助け下さい。 2008.09.28(Sun) 22:01 槻 誠三(けやき せいぞう) /////////////////////////////////////////////////////////////////////  こんにちは、イマジオムの高木です。 槻 誠三様: > Bitmap.PixelFormat = pf24bit のとき、すなわち 24 ビットカラーを > 前提としたコードです。 > > PixelFormat が他の値の時の対処のしかたが分かりません。  PixelFormat プロパティをご存知なのでしたら──   Bitmap.PixelFormat := pf24bit ──とやって、強制的に24ビットにすれば、対処はできると思います。  それとも pf8bit や pf32bit の場合の、ScanLine の参照先の格納形式を 知りたいということでしょうか? ―――――――――――――――――――――――――――――――――――― 株式会社イマジオム 代表取締役 高木太郎 〒316−0024 茨城県 日立市 水木町 1−11−10 電話:0294−28−0147 ファクシミリ:0294−28−0148 電子メール:tarou_takagi@imageom.co.jp ホームページ:http://www.imageom.co.jp/ ///////////////////////////////////////////////////////////////////// c-yan です. 本題の質問は高木さんがおっしゃるとおり Bitmap.PixelFormat := pf24bit で終わりです. > たとえば、pf8bit 256色カラーのときなんかはそもそも、Red, Green, Blue > の 3 要素に分ける事が可能なんでしょうか。 パレットの明るさ補正をすれば良いのでは? 画素はいじる必要ないですよね. > また逆に pf32bit の場合は、最上位の 8 ビットは何に使われているんでしょうか。 基本は使っていません. アルファチャネルになっていることもありますが. # 昨今のCPUでは32bitで割り切れないアドレスへのアクセスが遅いため # 無駄に空間を空けているのです. それとは別に気になったのが RGB だと分かっているなら PByteArray を使うのは大変じゃないかということです. type TRGBTriple = packed record B, G, R: Byte; end; TRGBTripleArray = array[0..400000] of TRGBTriple; PRGBTripleArray = ^TRGBTripleArray; みたいに定義して P を PRGBTripleArray にすれば P[x].R, P[x].G, P[x].B みたいにアクセスできますよ. 以上です. # PByteTripleArray にすれば RGB の処理を for I := 0 to 2 do で処理することも可 ///////////////////////////////////////////////////////////////////// 中村@ブレーンです。 seizo さんは書きました: >PixelFormat が他の値の時の対処のしかたが分かりません。 >たとえば、pf8bit 256色カラーのときなんかはそもそも、Red, Green, Blue >の 3 要素に分ける事が可能なんでしょうか。また逆に pf32bit の場合は、 >最上位の 8 ビットは何に使われているんでしょうか。 pf8bit の場合は各ピクセルにはカラーテーブルへのインデックスが入っているだけなので、 色を変更するにはカラーテーブルを変更することになります。こんな感じです。 pf4bit/pf1bit でも使えるはずです。 procedure Bright(Bitmap: TBitmap; Ratio: Extended); var  // カラーテーブルのコピー Quads: array[0..255] of TRGBQuad; i, ColorCount : Integer; // RGB 個別の色調整 function NewValue(b: Byte; ratio: Extended): Byte; var i: Integer; begin // ratio >= 0 を仮定 i := round(b * ratio); if i > 255 then Result := 255 else Result := i; end; begin  // カラーテーブルのコピーと色数を取得 ColorCount := GetDIBColorTable(Bitmap.Canvas.Handle, 0, 256, Quads[0]); // カラーテーブルのコピーの色を書き換える。 for i := 0 to ColorCount - 1 do begin Quads[i].rgbBlue := NewValue(Quads[i].rgbBlue, Ratio); Quads[i].rgbRed := NewValue(Quads[i].rgbRed, Ratio); Quads[i].rgbGreen := Newvalue(Quads[i].rgbGreen, Ratio); end;  // カラーテーブルのコピーをカラーテーブルへ書き戻す。 SetDIBColorTable(Bitmap.Canvas.Handle, 0, ColorCount, Quads[0]);  // パレットの再生成(これをやらないと 256色ディスプレイで正しく表示されません) DeleteObject(Bitmap.ReleasePalette); end; ---------- 東京都 日野市 中村拓男 ///////////////////////////////////////////////////////////////////// 槻 誠三(けやき せいぞう)です。 イマジオムの高木さん、c-yan さん、中村拓男さん、アドバイスありがとう 御座います。 //////// イマジオムの高木さんのコメント >  Bitmap.PixelFormat := pf24bit > >──とやって、強制的に24ビットにすれば、対処はできると思います。 これは、気が付きませんでした。 > それとも pf8bit や pf32bit の場合の、ScanLine の参照先の格納形式を >知りたいということでしょうか? 何ビットのカラーが、Red, Green, Blue の 3 要素に分ける事が可能かどうか を知りたかったのですが、中村拓男さんのコメントで、ハッキリしました。 //////// c-yan さんのコメント >パレットの明るさ補正をすれば良いのでは? 画素はいじる必要ないですよね. これも、気が付きませんでした。 >type > TRGBTriple = packed record > B, G, R: Byte; > end; > TRGBTripleArray = array[0..400000] of TRGBTriple; > PRGBTripleArray = ^TRGBTripleArray; > >みたいに定義して > >P を PRGBTripleArray にすれば > >P[x].R, P[x].G, P[x].B みたいにアクセスできますよ. c-yan さんのおっしゃるとおりだと思います。 //////// 中村拓男さんのコメント >pf8bit の場合は各ピクセルにはカラーテーブルへのインデックスが入っているだけなので、 >色を変更するにはカラーテーブルを変更することになります。こんな感じです。 > >pf4bit/pf1bit でも使えるはずです。 はじめて疑問がとけました。また、本当に貴重な情報をありがとう 御座います。 2008.09.29(mON) 21:55 槻 誠三(けやき せいぞう) /////////////////////////////////////////////////////////////////////