Lazarus
Programming => Graphics and Multimedia => Graphics => Topic started by: Hitnrun on June 15, 2007, 08:30:23 pm
-
Hello!
I am trying to port an application from windows, where I have a pointer to bitmap data in BGR24 format (default windows DIB).
In windows I do:
procedure display(pData: Pointer);
var
b: TBitmap;
bi: TBitmapInfo;
begin
FillChar(bi, sizeof(bi), 0);
bi.bmiHeader.biWidth := FWindowWidth;
bi.bmiHeader.biHeight := -FWindowHeight;
bi.bmiHeader.biPlanes := 1;
bi.bmiHeader.biBitCount := 24;
bi.bmiHeader.biSizeImage := 0;
bi.bmiHeader.biSize := sizeof(TBitmapInfoHeader);
bi.bmiHeader.biClrUsed := 0;
bi.bmiHeader.biClrImportant := 0;
b := TBitmap.Create;
b.Height := 0;
b.Width := FWindowWidth;
b.Height := FWindowHeight;
if SetDIBits(b.Canvas.Handle, b.Handle, 0, FWindowHeight, pData, bi, DIB_RGB_COLORS) = 0 then raise Exception.Create('error');
FWindow.Canvas.StretchDraw(Rect(0, 0, FDisplayWidth, FDisplayHeight), b);
b.Free;
end;
Note that on windows, I pass the parameter
bi.bmiHeader.biHeight := -FWindowHeight;
as negative, so the SetDIBits function displays the image right. If I leave it positive, the image displays mirrored just like I am getting with lazarus.
On lazarus, my code looks like:
procedure display(pData: Pointer);
var
B: HBITMAP;
bmp: TBitmap;
begin
bmp := TBitmap.Create;
B := CreateBitmap(FWindowWidth, FWindowHeight, 1, 24, pData);
if B = 0 then
raise Exception('Error creating bitmap');
bmp.CreateFromBitmapHandles(B, 0, Rect(0, 0, FWindowWidth, FWindowHeight));
FWindow.Canvas.StretchDraw(Rect(0, 0, FDisplayWidth, FDisplayHeight), FOffscreen);
DeleteObject(B);
bmp.Free;
end;
but the image displays mirrored.
Is there an equivallent parameter of the negative parameter of SetDIBits? What is wrong, my image was inverted, or the CreateBitmap inverts it?
Thanks!
-
windows bitmaps are stored in a reversed order. So when crating one you need to pass the image lines in a reversed order.
For DIBs you can indeed tell windows that the ordering is from top to bottom.
-
windows bitmaps are stored in a reversed order. So when crating one you need to pass the image lines in a reversed order.
For DIBs you can indeed tell windows that the ordering is from top to bottom.
Ok, in Windows I pass the height as a negative value, so how I do this in Lazarus/FPC? I tried passing the height as negative in various funcions, all of them gave errors...
-
what functions did you use ?
The easiest way to load raw image data into a bitmap is using TRawImage. There you can setup a description which matches exactly your data.
-
The ones I posted on the first post! :wink:
procedure display(pData: Pointer);
var
B: HBITMAP;
bmp: TBitmap;
begin
bmp := TBitmap.Create;
B := CreateBitmap(FWindowWidth, FWindowHeight, 1, 24, pData);
if B = 0 then
raise Exception('Error creating bitmap');
bmp.CreateFromBitmapHandles(B, 0, Rect(0, 0, FWindowWidth, FWindowHeight));
FWindow.Canvas.StretchDraw(Rect(0, 0, FDisplayWidth, FDisplayHeight), FOffscreen);
DeleteObject(B);
bmp.Free;
end;
pData is a pointer to image bytes, the width, height and depth I know from previous funcions calls.
-
Ah, Create bitmap creates the (original) windows bitmaps, with the scanlines reversed. There is no way to tell what the layout or yuor data is.
It is faster (removes 2 conversions) to use TBitmap.LoadFromIntfImage(IntfImage: TLazIntfImage);
procedure display(pData: Pointer);
var
bmp: TBitmap;
IntfImage: TLazIntfImage;
begin
FillByte(IntfImage, SizeOf(IntfImage), 0);
// fill in parts of IntfImage.Description
with IntfImage.Description do
begin
Format := ricfRGBA;
Depth := 24; // used bits per pixel
Width := FWindowWidth;
Height := FWindowHeight;
BitOrder := riboBitsInOrder;
ByteOrder := DefaultByteOrder;
LineOrder := riloTopToBottom; // here you can set the direction of lines
BitsPerPixel := 24; // bits per pixel. can be greater than Depth.
// (dont know if pixels are represented by RGB or RGBx otherwise it should be 32
LineEnd := rileWordBoundary;
RedPrec:=8; // red precision. bits for red
RedShift:=16;
GreenPrec:=8;
GreenShift:=8; // bitshift. Direction: from least to most significant
BluePrec:=8;
// BlueShift:=0;
// AlphaPrec:=0;
// MaskBitsPerPixel:=0;
end;
IntfImage.Data := pData;
IntfImage.DataSize := FWindowWidth * FWindowHeight * 3; (see BitsPerPixel remark)
bmp := TBitmap.Create;
bmp.LoadFromIntfImage(IntfImage);
end;
-
In doing this, I get this exception:
"TGtkWidgetSet.CreateBitmapFromRawImage Incompatible BitsPerPixel"
Tracing into the sourcecode, I saw that the call
Visual:=gdk_visual_get_best_with_depth(ImgDepth);
Returns a depth of 32 bpp (instead if my image's 24 bpp), and compares with my image's depth
if (RawImage.Description.BitsPerPixel<>GetPGdkImageBitsPerPixel(GdkImage))
then begin
RaiseGDBException('TGtkWidgetSet.CreateBitmapFromRawImage Incompatible BitsPerPixel');
end;
And of course they are different... why is it changing my format do 32 bits, if I told that it is 24? (my pixel data is in real 24 bpp)
Ah for the code you provided to compile, I had to make a few changes:
var
bmp: TBitmap;
RI: TRawImage;
IntfImage: TLazIntfImage;
begin
FillChar(RI, SizeOf(RI), 0);
// fill in parts of IntfImage.Description
with RI.Description do
begin
Format := ricfRGBA;
Depth := 24; // used bits per pixel
Width := FWindowWidth;
Height := FWindowHeight;
BitOrder := riboBitsInOrder;
ByteOrder := DefaultByteOrder;
LineOrder := riloTopToBottom; // here you can set the direction of lines
BitsPerPixel := 24; // bits per pixel. can be greater than Depth.
// (dont know if pixels are represented by RGB or RGBx otherwise it should be 32
LineEnd := rileWordBoundary;
RedPrec:=8; // red precision. bits for red
RedShift:=16;
GreenPrec:=8;
GreenShift:=8; // bitshift. Direction: from least to most significant
BluePrec:=8;
// BlueShift:=0;
// AlphaPrec:=0;
// MaskBitsPerPixel:=0;
end;
RI.Data := pData
RI.DataSize := FFrameSize; // FWindowWidth * FWindowHeight * 3; {see BitsPerPixel remark}
IntfImage := TLazIntfImage.Create(FWindowWidth, FWindowHeight);
IntfImage.SetRawImage(RI);
bmp := TBitmap.Create;
bmp.LoadFromIntfImage(IntfImage);
-
In doing this, I get this exception:
"TGtkWidgetSet.CreateBitmapFromRawImage Incompatible BitsPerPixel"
Tracing into the sourcecode, I saw that the call
Visual:=gdk_visual_get_best_with_depth(ImgDepth);
Returns a depth of 32 bpp
Interesting. I've spend some time to find a 32bpp X server, but couldn't find any to test with. What Xserver do you use ?
(instead if my image's 24 bpp), and compares with my image's depth
And of course they are different... why is it changing my format do 32 bits, if I told that it is 24? (my pixel data is in real 24 bpp)
Ehm... that is one of the problems that Paul and I are currently trying to solve (in a separate branch). The way the bitmap code works now is that it always creates a bitmap in the depth of your device. And unlike windows, X only accepts 1bpp or device bpp depths. So there is no conversion done yet.
You could use another intfimage to convert your image to a device depth, but I admit that's something you nomally don't want.
Ah for the code you provided to compile, I had to make a few changes:
Ah, I didn't test it. I only wrote it down here, but you got the idea.
-
Interesting. I've spend some time to find a 32bpp X server, but couldn't find any to test with. What Xserver do you use ?
According to dpkg -l (on Ubuntu 7.04):
xserver-xorg 7.2-0ubuntu11 the X.Org X server