Reputation: 85
I am completely new to delphi and I have a project where I need to load a picture from a pointer to a C-array holding raw pixel data.
I can't simply use TPicture.LoadFromFile
because the actual loading is performed within a C++ DLL. All I get back from the DLL is a pointer to the image width, height, format and the pointer to the array holding the pixel data.
DLL_Image = packed record
Width : UInt32; { Width of image. [px] }
Height : UInt32; { Height of image. [px] }
Format : ImageFormat; { (Color) Format of image. }
Data : ^UInt8; { Points to image data. }
end;
DLL_PImage = ^DLL_Image;
What I tried is loading the image data into a TMemoryStream
followed by TPicture.LoadFromStream()
which does not work. IIRC I had to write a proper instance of TPicture
to the stream to make this work.
Is there a way to load the image from the data array?
Upvotes: 3
Views: 908
Reputation: 108963
You can easily create a VCL TBitmap
object with the given pixel data by coping the pixel data to the scanlines of the TBitmap
.
Here is a simple example.
First we create some sample raw pixel data:
function MakePixelData(const AWidth, AHeight: Integer): pointer;
var
p: PRGBQuad;
y, x: Integer;
begin
GetMem(Result, AWidth * AHeight * sizeof(TRGBQuad));
p := PRGBQuad(Result);
y := 0;
while y < AHeight do
begin
x := 0;
while x < AWidth do
begin
p.rgbRed := 255 * x div AWidth;
p.rgbGreen := 255 * y div AHeight;
p.rgbBlue := 255;
Inc(x);
Inc(p);
end;
Inc(y);
end;
end;
procedure FreePixelData(var AData: pointer);
begin
FreeMem(AData);
end;
The MakePixelData
function allocates some memory on the heap for a bitmap of a given size and fills it with a simple gradient:
The FreePixelData
procedure is then used to free this memory.
Now to the interesting part, using this raw pixel data to obtain a VCL TBitmap
object:
procedure TForm1.FormCreate(Sender: TObject);
const
W = 400;
H = 200;
var
RawPixelData: pointer;
bm: TBitmap;
y: Integer;
function PixelData(ARowIndex: Integer): pointer;
begin
Result := PByte(RawPixelData) + ARowIndex * W * sizeof(TRGBQuad);
end;
begin
RawPixelData := MakePixelData(W, H);
try
bm := TBitmap.Create;
try
bm.SetSize(W, H);
bm.PixelFormat := pf32bit;
for y := 0 to bm.Height - 1 do
CopyMemory(bm.ScanLine[y], PixelData(y), bm.Width * sizeof(TRGBQuad));
bm.SaveToFile('D:\Desktop\Bitmap from raw pixel data.bmp');
finally
bm.Free;
end;
finally
FreePixelData(RawPixelData);
end;
end;
This will create a VCL TBitmap
from the raw pixel data. Just to demonstrate that it works, I save it as a file. But you could just as well display it in a TImage
control or use it for some custom VCL drawing.
Just be careful to use the same pixel format everywhere. In my example, I use 32-bit RGBX data.
Upvotes: 6