Recent

Author Topic: Different TBitmap.RawImage.Data behavior in Win32 and Linux  (Read 27215 times)

dan59314

  • New Member
  • *
  • Posts: 38
Different TBitmap.RawImage.Data behavior in Win32 and Linux
« on: October 27, 2009, 02:18:55 am »
Hi,

  I tried to manipulate TBitmap.RawImage.Data as following, load a bmp file, copy to a new TBitmap, and save to a new file. But get different result in Win32 and Linux.

  With the same source code....
Code: [Select]
procedure TForm1.Button1Click(Sender: TObject);
var
  bmp1, bmp2:TBitmap;
  ptr1, ptr2:Pointer;
  i:integer;
begin

  //if OpenDialog1.Execute then
  begin
    try
      bmp1:=TBitmap.Create;
      bmp2:=TBitmap.Create;

      bmp1.LoadFromFile('test.bmp'); //OpenDialog1.FileName);
      bmp2.PixelFormat := bmp1.PixelFormat;
      bmp2.Width := bmp1.Width;
      bmp2.Height := bmp1.Height;

      for i:=0 to bmp1.Height-1 do
      begin
        ptr1 := bmp1.RawImage.Data + bmp1.Width*3*i;
        ptr2 := bmp2.RawImage.Data+ bmp2.Width*3*i;

        Move(ptr1^, ptr2^, bmp1.Width*3);
      end;

      bmp2.SaveToFile('aa.bmp');

    finally
      bmp1.Free;
      bmp2.Free;
    end;
  end;

end;

Got different result, 
   
   In Windows http://dan59314.myweb.hinet.net/WindowsImage.jpg

   In Linux http://dan59314.myweb.hinet.net/LinuxImage.jpg

   How to fix the problem? Is it a bug?

Thanks,

Regards,

Daniel

Marc

  • Administrator
  • Hero Member
  • *
  • Posts: 2510
Re: Different TBitmap.RawImage.Data behavior in Win32 and Linux
« Reply #1 on: October 27, 2009, 10:38:58 am »
Code: [Select]
ptr1 := bmp1.RawImage.Data + bmp1.Width*3*i;

the problems here are the assumptions you make:
  Each pixel will take 3 bytes and each row is byte alligned
This is complete platform dependent, look at the rawimage.description how the data is layout in memory
//--
{$I stdsig.inc}
//-I still can't read someones mind
//-Bugs reported here will be forgotten. Use the bug tracker

dan59314

  • New Member
  • *
  • Posts: 38
Re: Different TBitmap.RawImage.Data behavior in Win32 and Linux
« Reply #2 on: October 28, 2009, 03:51:43 am »
Code: [Select]
ptr1 := bmp1.RawImage.Data + bmp1.Width*3*i;

the problems here are the assumptions you make:
  Each pixel will take 3 bytes and each row is byte alligned
This is complete platform dependent, look at the rawimage.description how the data is layout in memory

Hi, Marc,

  Thanks again.

  Yes, I loaded the 24bit bmp file, size 480x360, 3 bytes per pixel, I guess the stridebytes should be bmp.Width*3 = 480*3 = 1440.   

  I search and found in GraphType.pp the TRawImageDescription, still don't know how the linux align the raw data.

  Then I google 'Linux Raw Data format', 'Linux Raw Data mainpulate'.., can't find any hint can make the code work.

   Then I wondered that may works if I add  'bmp2.RawImage.Description := bmp1.RawImage.Description;' after set bmp2 size. But still the same.

   Didn't tried it out yet.

  May you revise the code and show me how to make it works the same result in both linux and windows?



Regards,

Daniel

 

Vincent Snijders

  • Administrator
  • Hero Member
  • *
  • Posts: 2661
    • My Lazarus wiki user page
Re: Different TBitmap.RawImage.Data behavior in Win32 and Linux
« Reply #3 on: October 28, 2009, 08:58:35 am »
You must use the bmp1.RawImage.Description fields to determine how to copy the bytes. See http://lazarus-ccr.sourceforge.net/docs/lcl/graphtype/trawimagedescription.html for a explanation of the fields.

In your copying code you assume  BitsPerPixel=24 and  LineEnd=rileByteBoundary. Is that true?

dan59314

  • New Member
  • *
  • Posts: 38
Re: Different TBitmap.RawImage.Data behavior in Win32 and Linux
« Reply #4 on: October 28, 2009, 10:21:39 am »
You must use the bmp1.RawImage.Description fields to determine how to copy the bytes. See http://lazarus-ccr.sourceforge.net/docs/lcl/graphtype/trawimagedescription.html for a explanation of the fields.

In your copying code you assume  BitsPerPixel=24 and  LineEnd=rileByteBoundary. Is that true?

Thanks,

  I read the explanation, and assign 3 fields.

      bmp2.RawImage.Description.Format:=  ricfRGBA;                                                 
      bmp2.RawImage.Description.BitsPerPixel:=BitsPerPixel;                                         
      bmp2.RawImage.Description.LineEnd:=rileDWordBoundary;                   

Code: [Select]
                                                                                     
function BytesPerScanline(PixelsPerScanline, BitsPerPixel,                                         
  Alignment: Integer): Longint;                                                                     
begin                                                                                               
  Dec(Alignment);                                                                                   
  Result := ((PixelsPerScanline * BitsPerPixel) + Alignment) and not Alignment;                     
  Result := Result div 8;                                                                           
end;                                                                                           
procedure TForm1.Button1Click(Sender: TObject);                                                     
var                                                                                                 
  bmp1, bmp2:TBitmap;                                                                               
  ptr1, ptr2, p0:Pointer;                                                                           
  i,j,strideBytes,BYtesPerPixel,BitsPerPixel:integer;                                               
begin                                                                                       
  //if OpenDialog1.Execute then                                                                     
  begin                                                                                             
    try                                                                                             
      bmp1:=TBitmap.Create;                                                                         
      bmp2:=TBitmap.Create;                                                     
      bmp1.LoadFromFile('test.bmp'); //OpenDialog1.FileName);                                       
      bmp2.PixelFormat := bmp1.PixelFormat;                                                         
      bmp2.Width := bmp1.Width;                                                                     
      bmp2.Height := bmp1.Height;                                           
      BitsPerPixel :=24;                                                                           
      bmp2.RawImage.Description.Format:=  ricfRGBA;                                                 
      bmp2.RawImage.Description.BitsPerPixel:=BitsPerPixel;                                         
      bmp2.RawImage.Description.LineEnd:=rileDWordBoundary;               
      strideBytes := BytesPerScanline(bmp1.Width, BitsPerPixel, 32);                               
      BytesPerPixel := BitsPerPixel div 8;                                                 
      //bmp2.RawImage.Description := bmp1.RawImage.Description;         
      for i:=0 to bmp1.Height-1 do                                                                 
      begin                                                                                         
        ptr1 := bmp1.RawImage.Data+strideBytes*i;                                                   
        ptr2 := bmp2.RawImage.Data+strideBytes*i;                 
        Move(ptr1^, ptr2^, strideBytes);                                                           
      end;                                                                     
      bmp2.SaveToFile('aa.bmp');                                               
    finally                                                                                         
      bmp1.Free;                                                                                   
      bmp2.Free;                                                                                   
    end;                                                                                           
  end;                                                                                         
end;                                                                                               


  In Windows, I guess it's 32 bits aligned, means rileDWordBoundary.  I suppose Linux also the same.

 if I assign the
      bmp2.RawImage.Description := bmp1.RawImage.Description;   
  and
      copy the RawImage data with the for loop, increasing pointer.

  The bmp2 should be as same as bmp1, isn't it?


   BTW, in Windows, the Raw Image aligned in   BGRBGRBGRBGR........
 
   Is the Linux aligned in a different manner?  EX   BBBBBBBBBBBBB.....  GGGGGGGG.... RRRRRR...,   first Blue data block, then the Green, the Red... ? ( Because the image seems have multiple shifted image.)

Thanks,

Regards,

Daniel

Vincent Snijders

  • Administrator
  • Hero Member
  • *
  • Posts: 2661
    • My Lazarus wiki user page
Re: Different TBitmap.RawImage.Data behavior in Win32 and Linux
« Reply #5 on: October 28, 2009, 10:30:27 am »
You are trying something different than I meant.

You change description according to the way you copy the data.

I suggested that you read the description of both bitmaps and adjust the way you copy the data accordingly.

dan59314

  • New Member
  • *
  • Posts: 38
Re: Different TBitmap.RawImage.Data behavior in Win32 and Linux
« Reply #6 on: October 29, 2009, 01:37:44 am »
You are trying something different than I meant.
You change description according to the way you copy the data.
I suggested that you read the description of both bitmaps and adjust the way you copy the data accordingly.

With the following code, I got a more comfortable result. http://dan59314.myweb.hinet.net/LinuxImage1.jpg

I suppose the raw data aligned in  BBBBBBBBBBBBBBBBBBBBB....(count: WidthxHeight) GGGGGGGGGGGGGGGGGGGGGGG.......RRRRRRRRRRRRRRRRRR from the start to end.

Code: [Select]
function BytesPerScanline(PixelsPerScanline, BitsPerPixel, Alignment: Integer): Longint;
begin
  Dec(Alignment);
  Result := ((PixelsPerScanline * BitsPerPixel) + Alignment) and not Alignment;
  Result := Result div 8;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  bmp1, bmp2:TBitmap;
  ptr1, ptr2, p0:Pointer;
  i,j,strideBytes,BYtesPerPixel,BitsPerPixel:integer;
begin
  //if OpenDialog1.Execute then
  begin
    try
      bmp1:=TBitmap.Create;
      bmp2:=TBitmap.Create;
      bmp1.LoadFromFile('test.bmp'); //OpenDialog1.FileName);
      bmp2.PixelFormat := bmp1.PixelFormat;
      bmp2.Width := bmp1.Width;
      bmp2.Height := bmp1.Height;
      bmp2.RawImage.Description.Init_BPP32_B8G8R8_BIO_TTB(bmp2.Width, bmp2.Height);

      BitsPerPixel :=24;
      bmp2.RawImage.Description.Format:=  ricfRGBA;
      bmp2.RawImage.Description.BitsPerPixel:=BitsPerPixel;
      bmp2.RawImage.Description.LineEnd:=rileDWordBoundary;
      strideBytes := BytesPerScanline(bmp1.Width, BitsPerPixel, 32);
      BytesPerPixel := BitsPerPixel div 8;
      bmp2.RawImage.Description := bmp1.RawImage.Description;
      bmp2.BeginUpdate(false);

      {for i:=0 to bmp1.Height-1 do
      begin
        ptr1 := bmp1.RawImage.Data+strideBytes*i;
        ptr2 := bmp2.RawImage.Data+strideBytes*i;
        Move(ptr1^, ptr2^, strideBytes);
      end;
      }


      // First assign a contiuos block for Blue ----------------------

      ptr2 := bmp2.RawImage.Data;
      for i:=0 to bmp1.Height-1 do
      begin
        ptr1 := bmp1.RawImage.Data+bmp1.Width*3*i;
        for j:=0 to bmp1.Width-1 do
        begin
          Move(ptr1^, ptr2^, 1);
          //Move((ptr1+1)^, (ptr2+bmp2.Width)^, 1);
          //Move((ptr1+2)^, (ptr2+bmp2.Width*2)^, 1);
          ptr1 := Pointer( integer(ptr1)+3);
          ptr2 := Pointer( integer(ptr2)+1);
        end;
      end;

      //  block for Green -----------------------------

      ptr2 := bmp2.RawImage.Data+bmp2.Width*bmp2.Height;
      for i:=0 to bmp1.Height-1 do
      begin
        ptr1 := bmp1.RawImage.Data+bmp1.Width*3*i;
        for j:=0 to bmp1.Width-1 do
        begin
          //Move(ptr1^, ptr2^, 1);
          //Move((ptr1+1)^, (ptr2+bmp2.Width)^, 1);
          Move((ptr1+2)^, (ptr2)^, 1);
          ptr1 := Pointer( integer(ptr1)+3);
          ptr2 := Pointer( integer(ptr2)+1);
        end;
      end;

      // block for Red -------------------------------------------
      ptr2 := bmp2.RawImage.Data+bmp2.Width*bmp2.Height*2;
      for i:=0 to bmp1.Height-1 do
      begin
        ptr1 := bmp1.RawImage.Data+bmp1.Width*3*i;
        for j:=0 to bmp1.Width-1 do
        begin
          //Move(ptr1^, ptr2^, 1);
          Move((ptr1+1)^, (ptr2)^, 1);
          //Move((ptr1+2)^, (ptr2+bmp2.Width*2)^, 1);
          ptr1 := Pointer( integer(ptr1)+3);
          ptr2 := Pointer( integer(ptr2)+1);
        end;
      end;
      bmp2.EndUpdate(false);
      bmp2.SaveToFile('aa.bmp');
    finally
      bmp1.Free;
      bmp2.Free;
    end;
  end;
end;  

I wonder I am almost there. Any idea to get it work?

Thanks,

Daniel

dan59314

  • New Member
  • *
  • Posts: 38
Re: Different TBitmap.RawImage.Data behavior in Win32 and Linux
« Reply #7 on: October 29, 2009, 02:00:19 am »
Also I just simply use BitBlt() to get desktop image on form1. It's a mass. http://dan59314.myweb.hinet.net/TempImage/BitBltImage1.jpg

Is it possible there is a bug in raw data alignment, so cause the incorrect result in BitBlt() and my previous trying.

Daniel

Code: [Select]
procedure TForm1.Button1Click(Sender: TObject);
begin
  BitBlt(Self.Canvas.Handle, 0,0,Self.ClientWidth, Self.ClientHeight,  GetDC(0), 0,0, 0);
end;  
« Last Edit: October 29, 2009, 02:04:03 am by dan59314 »

Marc

  • Administrator
  • Hero Member
  • *
  • Posts: 2510
Re: Different TBitmap.RawImage.Data behavior in Win32 and Linux
« Reply #8 on: October 29, 2009, 12:45:42 pm »
Does the following work ?
Code: [Select]
var
  B: TBitmap;
  DC: HDC;
begin
  B := TBitmap.Create;
  DC := GetDC(0);
  B.LoadFromDevice(DC);
  ReleaseDC(0, DC);
  ...
end;

//--
{$I stdsig.inc}
//-I still can't read someones mind
//-Bugs reported here will be forgotten. Use the bug tracker

dan59314

  • New Member
  • *
  • Posts: 38
Re: Different TBitmap.RawImage.Data behavior in Win32 and Linux
« Reply #9 on: October 30, 2009, 01:39:41 am »
Does the following work ?

Yes, it's perfect without missing any pixel.

Do you have any idea on why BitBlt() don't work fine?  and mine.

Daniel
« Last Edit: October 30, 2009, 01:42:04 am by dan59314 »

dan59314

  • New Member
  • *
  • Posts: 38
Re: Different TBitmap.RawImage.Data behavior in Win32 and Linux
« Reply #10 on: November 02, 2009, 08:28:55 am »


  Any one ever success on using BitBlt() in Ubuntu Linux?

dan59314

  • New Member
  • *
  • Posts: 38
Re: Different TBitmap.RawImage.Data behavior in Win32 and Linux
« Reply #11 on: November 09, 2009, 10:38:42 am »
May anyone help? BitBlt() can't work in ubuntu linux?

dan59314

  • New Member
  • *
  • Posts: 38
Re: Different TBitmap.RawImage.Data behavior in Win32 and Linux
« Reply #12 on: November 27, 2009, 01:53:22 am »
Hi,

   No one got the same problem on Linux ubuntu ?

   Can anyone kindly help?


Thanks,

Daniel

   

dan59314

  • New Member
  • *
  • Posts: 38
Why the same source get different result in Ubuntu9.4 and windows XP
« Reply #13 on: January 11, 2010, 10:18:57 am »
Hi,

  This is an old post, still not solved, wonder someone may help now.

  I tried to manipulate TBitmap.RawImage.Data as following, load a bmp file, copy to a new TBitmap, and save to a new file. But get different result in Win32 and Linux.

  With the same source code....



Code: [Select]
procedure TForm1.btnScan0TestClick(Sender: TObject);
var
  bmp1, bmp2:TBitmap;
  ptr1, ptr2:Pointer;
  i:integer;
begin

  //if OpenDialog1.Execute then
  begin
    try
      bmp1:=TBitmap.Create;
      bmp2:=TBitmap.Create;

      bmp1.LoadFromFile('test24.bmp'); //OpenDialog1.FileName);
      bmp2.PixelFormat := bmp1.PixelFormat;
      bmp2.Width := bmp1.Width;
      bmp2.Height := bmp1.Height;

      for i:=0 to bmp1.Height-1 do
      begin
        ptr1 := bmp1.RawImage.Data + bmp1.Width*3*i;
        ptr2 := bmp2.RawImage.Data+ bmp2.Width*3*i;

        Move(ptr1^, ptr2^, bmp1.Width*3);
      end;

      bmp2.SaveToFile('aa.bmp');

     
    finally
      bmp1.Free;
      bmp2.Free;
    end;
  end;

end; 

Got different result, 
   
   In Windows http://dan59314.myweb.hinet.net/WindowsImage.jpg

   In Linux http://dan59314.myweb.hinet.net/LinuxImage.jpg

   How to fix the problem? Is it a bug?

Thanks,

Regards,

Daniel

Marc

  • Administrator
  • Hero Member
  • *
  • Posts: 2510
Re: Why the same source get different result in Ubuntu9.4 and windows XP
« Reply #14 on: January 11, 2010, 11:08:38 am »
Please,
1) if this is an old thread, respond to that thread
2) read my notes about rawimage.destription. You are assuming a dataformat which isn't correct.

Merged....
« Last Edit: January 11, 2010, 11:10:42 am by Marc »
//--
{$I stdsig.inc}
//-I still can't read someones mind
//-Bugs reported here will be forgotten. Use the bug tracker

 

TinyPortal © 2005-2018