ここまでコードを書いてきてひとつ思ったのですが、テーブルを使った簡単な処理は分割できますね。というわけで以下の型と関数を新しく定義しましょう。
type
TByteTable = array[Byte]of Byte;
procedure StdTableFilter(Bitmap: TBitmap; Table: TByteTable);
implementation
procedure StdTableFilter(Bitmap: TBitmap; Table: TByteTable);
//単純なテーブル変換を行う関数
var
X, Y: Integer;
pLine: PLine24;
begin
Bitmap.PixelFormat := pf24bit;
{ ピクセルの変換処理 }
for Y := 0 to Bitmap.Height -1 do
begin
pLine := Bitmap.ScanLine[Y];
for X := 0 to Bitmap.Width -1 do
with pLine^[X] do
begin
R := Table[R];
G := Table[G];
B := Table[B];
end;
end;
end;
ここまでやってきたことを少しまとめておきましょう。テーブル変換が使えるフィルタを書き換えるとユニットはこんな感じになっているはずです。
unit Filters;
interface
uses Windows, SysUtils, Graphics;
type
PRGB24 = ^TRGB24;
TRGB24 = packed record
B: Byte;
G: Byte;
R: Byte;
end;
TLine24 = array[0..MaxInt div SizeOf(TRGB24) -1]of TRGB24;
PLine24 = ^TLine24;
TCacheLines = array[0..MaxInt div SizeOf(Pointer) -1]of Pointer;
PCacheLines = ^TCacheLines;
TOperator3 = array[-1..1, -1..1]of Integer;
TMatrix3 = array[-1..1, -1..1]of TRGB24;
TLineMatrix3 = array[-1..1]of PLine24;
TByteTable = array[Byte]of Byte;
//関数
function MakeOperator3(X: array of Integer): TOperator3;
function GetCacheLines(Source: TBitmap): PCacheLines;
procedure CopyDIB(Source, Dest: TBitmap);
procedure StdTableFilter(Bitmap: TBitmap; Table: TByteTable);
procedure NegaPosi(Bitmap: TBitmap);
procedure Solarization(Bitmap: TBitmap);
procedure Grayscale(Bitmap: TBitmap);
procedure Gamma(Bitmap: TBitmap; Value: Double);
procedure Brightness(Bitmap: TBitmap; Value: Integer);
implementation
uses Math;
resourcestring
EMes_InvalidGraphic = 'ビットマップが不正です。';
function MakeOperator3(X: array of Integer): TOperator3;
// オペレーターを作成
var
I, MX, MY, Count: Integer;
begin
FillChar(Result, SizeOf(Result), 0);
Count := High(X);
if Count = -1 then Exit;
I := 0;
for MX := -1 to 1 do
for MY := -1 to 1 do
begin
Result[MX, MY] := X[I];
Inc(I);
if I > Count then Break;
end;
end;
function GetCacheLines(Source: TBitmap): PCacheLines;
// ビットマップのスキャンラインをキャッシュする
var
Y: Integer;
begin
if (Source = nil) or Source.Empty then
raise EInvalidGraphicOperation.CreateRes(@EMes_InvalidGraphic);
with Source do
begin
GetMem(Result, SizeOf(Pointer) * Height);
try
for Y := 0 to Height -1 do
Result^[Y] := ScanLine[Y];
except
FreeMem(Result);
raise;
end;
end;
end;
procedure CopyDIB(Source, Dest: TBitmap);
// DIBをコピーする
var
Y, Bytes: Integer;
begin
if (Source = nil) or Source.Empty or (Dest = nil) then
raise EInvalidGraphicOperation.CreateRes(@EMes_InvalidGraphic);
Source.PixelFormat := pf24bit;
Dest.PixelFormat := pf24bit;
Dest.Width := Source.Width;
Dest.Height := Source.Height;
Bytes := BytesPerScanline(Source.Width, 24, 32);
for Y := 0 to Source.Height -1 do
Move(Source.ScanLine[Y]^, Dest.ScanLine[Y]^, Bytes);
end;
procedure StdTableFilter(Bitmap: TBitmap; Table: TByteTable);
//単純なテーブル変換を行う関数
var
X, Y: Integer;
pLine: PLine24;
begin
Bitmap.PixelFormat := pf24bit;
{ ピクセルの変換処理 }
for Y := 0 to Bitmap.Height -1 do
begin
pLine := Bitmap.ScanLine[Y];
for X := 0 to Bitmap.Width -1 do
with pLine^[X] do
begin
R := Table[R];
G := Table[G];
B := Table[B];
end;
end;
end;
procedure NegaPosi(Bitmap: TBitmap);
// ネガポジ反転
var
X, Y: Integer;
pLine: PLine24;
begin
Bitmap.PixelFormat := pf24bit;
for Y := 0 to Bitmap.Height -1 do
begin
pLine := Bitmap.ScanLine[Y];
for X := 0 to Bitmap.Width -1 do
with pLine^[X] do
begin
R := R xor $FF;
G := G xor $FF;
B := B xor $FF;
end;
end;
if Assigned(Bitmap.OnChange) then
Bitmap.OnChange(Bitmap);
end;
procedure Solarization(Bitmap: TBitmap);
// ソラリゼーション
var
X, Y: Integer;
Table: TByteTable;
begin
{ 変換テーブルを生成 }
for X := 0 to 255 do
begin
//Table[X] := Min(X, X xor $FF);
Y := X xor $FF;
if X < Y then Y := X;
Table[X] := Y;
end;
//ピクセルの変換処理
StdTableFilter(Bitmap, Table);
if Assigned(Bitmap.OnChange) then
Bitmap.OnChange(Bitmap);
end;
procedure Grayscale(Bitmap: TBitmap);
//グレイスケール
var
X, Y, Gray: Integer;
pLine: PLine24;
begin
Bitmap.PixelFormat := pf24bit;
{ ピクセルの変換処理 }
for Y := 0 to Bitmap.Height -1 do
begin
pLine := Bitmap.ScanLine[Y];
for X := 0 to Bitmap.Width -1 do
with pLine^[X] do
begin
Gray := Round((R * 30 + G * 59 + B * 11) / 100);
{ 0..255の範囲に飽和(もしかすると必要ないかも(^^;) }
if Gray > 255 then Gray := 255
else if Gray < 0 then Gray := 0;
R := Gray;
G := Gray;
B := Gray;
end;
end;
if Assigned(Bitmap.OnChange) then
Bitmap.OnChange(Bitmap);
end;
procedure Gamma(Bitmap: TBitmap; Value: Double);
//ガンマ補正
var
X, Y: Integer;
Table: TByteTable;
begin
{ 変換テーブルの作成 }
Value := Value / 2.2;
for Y := 0 to 255 do
begin
X := Round(Power(Y / 255, Value) * 255);
if X > 255 then X := 255 else if X < 0 then X := 0;
Table[Y] := X;
end;
//ピクセルの変換処理
StdTableFilter(Bitmap, Table);
if Assigned(Bitmap.OnChange) then
Bitmap.OnChange(Bitmap);
end;
procedure Brightness(Bitmap: TBitmap; Value: Integer);
//明るさ補正
var
X, Y: Integer;
Table: TByteTable;
begin
if (Value = 0) or (Value > 255) or (Value < -255) then Exit;
{ 変換テーブルの作成 }
for Y := 0 to 255 do
begin
X := Y + Value;
if X > 255 then X := 255 else if X < 0 then X := 0;
Table[Y] := X;
end;
//ピクセルの変換処理
StdTableFilter(Bitmap, Table);
if Assigned(Bitmap.OnChange) then
Bitmap.OnChange(Bitmap);
end;
end.
|