Recent

Author Topic: Imported raw bitmap displays mirrored (upside-down)  (Read 11953 times)

Hitnrun

  • New Member
  • *
  • Posts: 24
Imported raw bitmap displays mirrored (upside-down)
« 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:

Code: [Select]

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:

Code: [Select]

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!

Marc

  • Administrator
  • Hero Member
  • *
  • Posts: 2496
RE: Imported raw bitmap displays mirrored (upside-down)
« Reply #1 on: June 18, 2007, 10:49:26 am »
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.
//--
{$I stdsig.inc}
//-I still can't read someones mind
//-Bugs reported here will be forgotten. Use the bug tracker

Hitnrun

  • New Member
  • *
  • Posts: 24
Re: RE: Imported raw bitmap displays mirrored (upside-down)
« Reply #2 on: June 18, 2007, 02:31:03 pm »
Quote from: "Marc"
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...

Marc

  • Administrator
  • Hero Member
  • *
  • Posts: 2496
RE: Re: RE: Imported raw bitmap displays mirrored (upside-do
« Reply #3 on: June 18, 2007, 02:46:18 pm »
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.
//--
{$I stdsig.inc}
//-I still can't read someones mind
//-Bugs reported here will be forgotten. Use the bug tracker

Hitnrun

  • New Member
  • *
  • Posts: 24
Imported raw bitmap displays mirrored (upside-down)
« Reply #4 on: June 18, 2007, 03:01:14 pm »
The ones I posted on the first post!  :wink:

Code: [Select]

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.

Marc

  • Administrator
  • Hero Member
  • *
  • Posts: 2496
Imported raw bitmap displays mirrored (upside-down)
« Reply #5 on: June 19, 2007, 12:56:19 pm »
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);
Code: [Select]

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;
//--
{$I stdsig.inc}
//-I still can't read someones mind
//-Bugs reported here will be forgotten. Use the bug tracker

Hitnrun

  • New Member
  • *
  • Posts: 24
Imported raw bitmap displays mirrored (upside-down)
« Reply #6 on: June 19, 2007, 02:18:48 pm »
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:

Code: [Select]

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);

Marc

  • Administrator
  • Hero Member
  • *
  • Posts: 2496
Imported raw bitmap displays mirrored (upside-down)
« Reply #7 on: June 19, 2007, 03:00:55 pm »
Quote from: "Hitnrun"
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 ?

Quote

(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.

Quote

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.
//--
{$I stdsig.inc}
//-I still can't read someones mind
//-Bugs reported here will be forgotten. Use the bug tracker

Hitnrun

  • New Member
  • *
  • Posts: 24
Imported raw bitmap displays mirrored (upside-down)
« Reply #8 on: June 20, 2007, 06:43:32 pm »
Quote from: "Marc"
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