サンプル1
可変長配列付き構造体で領域を動的に確保する例
PBitmapInfo = ^TBitmapInfo;
TBitmapInfo = record
bmiHeader: TBitmapInfoHeader;
bmiColors: array[0..0] of TRGBQuad;
end;
GetMemを使ったコード
コードを見る
procedure Example;
var
bmpInfo: PBitmapInfo;
size, i: Integer;
begin
// パレット256色分のサイズを計算
size := SizeOf(TBitmapInfoHeader) + SizeOf(TRGBQuad) * (256 - 1);
// 領域確保
GetMem(bmpInfo, size);
try
FillChar(bmpInfo^, size, 0);
// ヘッダー設定
with bmpInfo.bmiHeader do
begin
biSize := SizeOf(TBitmapInfoHeader);
biWidth := 100;
biHeight := 100;
biPlanes := 1;
biBitCount := 8;
biCompression := BI_RGB;
end;
// パレット設定(ここではグレースケール)
{$R-}
for i := 0 to 255 do
begin
bmpInfo.bmiColors[i].rgbRed := i;
bmpInfo.bmiColors[i].rgbGreen := i;
bmpInfo.bmiColors[i].rgbBlue := i;
bmpInfo.bmiColors[i].rgbReserved := 0;
end;
{$R+}
// bmpInfoを使っていろいろ処理
finally
FreeMem(bmpInfo);
end;
end;
動的配列を使ったコードではこうなります
procedure Example;
var
bmpInfo: PBitmapInfo;
buffer: TBytes;
size, i: Integer;
begin
// パレット256色分のサイズを計算
size := SizeOf(TBitmapInfoHeader) + SizeOf(TRGBQuad) * (256 - 1);
// 領域確保
// GetMem(bmpInfo, size);
SetLength(buffer, size);
// 先頭アドレスをbmpInfoにセット
bmpInfo := @buffer[0];
// ヘッダー設定
with bmpInfo.bmiHeader do
begin
... 上と同じ
end;
// パレット設定(ここではグレースケール)
{$R-}
for i := 0 to 255 do
begin
... 上と同じ
end;
{$R+}
// bmpInfoを使っていろいろ処理
// 開放処理が不要
end;
GetMem(bmpInfo, size);
FillChar(bmpInfo^, size, 0);
FreeMem(bmpInfo);
を
SetLength(buffer, size);
bmpInfo := @buffer[0];
に置き換えます
メリット
- 開放が不要になる
- 0クリアが不要になる(SetLengthは中身が初期化されるため)
デメリット
- 余計な変数の宣言が必要
buffer: TBytes;
- 余計な代入が発生
bmpInfo := @buffer[0];
- 知らない人が見ると??となるかも
サンプル2
GDI+を使って画像データのPixelデータを配列で取得
uses
GDIPAPI, GDIPOBJ;
procedure GetPixels(Bitmap: TGPBitmap);
var
Pixels: TArray<ARGB>;
Width, Height: Integer;
BitmapData: TBitmapData;
begin
Width := Bitmap.GetWidth;
Height := Bitmap.GetHeight;
SetLength(Pixels, Width * Height);
Bitmap.LockBits(MakeRect(0, 0, Width, Height), ImageLockModeRead, PixelFormat32bppARGB, BitmapData);
try
// ピクセルデータを読み込み
Move(BitmapData.Scan0^, Pixels[0], Width * Height * SizeOf(ARGB));
finally
Bitmap.UnlockBits(BitmapData);
end;
// Pixelsを使っていろいろ処理
end;
procedure Example;
var
Bitmap: TGPBitmap;
begin
Bitmap := TGPBitmap.Create('sample.png');
GetPixels(Bitmap);
Bitmap.Free;
end;
以下の個所が今回の肝となる個所です
SetLength(Pixels, Width * Height);
Move(BitmapData.Scan0^, Pixels[0], Width * Height * SizeOf(ARGB));
メリット
- メモリの確保と開放が不要
- 面倒なポインタアクセスが不要
- バイト単位ではなく1Pixel(ドット)単位でロジックが記述できるようになる
デメリット
- 特に思いつかない
GDI+に興味がある方は過去の記事を参照ください