Recent

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

LuizAmérico

  • Sr. Member
  • ****
  • Posts: 458
Re: Different TBitmap.RawImage.Data behavior in Win32 and Linux
« Reply #15 on: January 11, 2010, 03:48:48 pm »
You can use http://imaginglib.sourceforge.net/ it gives you any format you want both in win32 and linux

marcov

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 8607
  • FPC developer.
Re: Why the same source get different result in Ubuntu9.4 and windows XP
« Reply #16 on: January 11, 2010, 04:33:47 pm »
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....

Can't you specify how a bmp is to be loaded? Loading 24-bits bmps as 32-bit is not such a strange thing to expect.

Marc

  • Administrator
  • Hero Member
  • *
  • Posts: 2510
Re: Why the same source get different result in Ubuntu9.4 and windows XP
« Reply #17 on: January 11, 2010, 09:04:51 pm »
Can't you specify how a bmp is to be loaded? Loading 24-bits bmps as 32-bit is not such a strange thing to expect.
Nope, loading a 24bpp bitmap will result in a 24bpp bitmap, independent of the pixelformat set before loading
//--
{$I stdsig.inc}
//-I still can't read someones mind
//-Bugs reported here will be forgotten. Use the bug tracker

Marc

  • Administrator
  • Hero Member
  • *
  • Posts: 2510
Re: Different TBitmap.RawImage.Data behavior in Win32 and Linux
« Reply #18 on: January 12, 2010, 01:08:09 am »
OK, I changed the code a bit since it is a bit faster and you should use begin/end update:
Code: Pascal  [Select][+][-]
  1. var
  2.   bmp1, bmp2:TBitmap;
  3.   ptr1, ptr2:Pointer;
  4.   i:integer;
  5.   R1, R2: TRawImage;
  6. begin
  7.  
  8.   //if OpenDialog1.Execute then
  9.   begin
  10.     try
  11.       bmp1:=TBitmap.Create;
  12.       bmp2:=TBitmap.Create;
  13.  
  14.       bmp1.LoadFromFile('test24.bmp'); //OpenDialog1.FileName);
  15.       bmp2.PixelFormat := bmp1.PixelFormat;
  16.       bmp2.Width := bmp1.Width;
  17.       bmp2.Height := bmp1.Height;
  18.  
  19.       R1 := bmp1.RawImage;
  20.       bmp2.BeginUpdate;
  21.       R2 := bmp2.RawImage;
  22.  
  23.       for i:=0 to bmp1.Height-1 do
  24.       begin
  25.         // something else since this won't work
  26.         // ptr1 := R1.Data + bmp1.Width*3*i;
  27.         // ptr2 := R2.Data + bmp2.Width*3*i;
  28.  
  29.         // Move(ptr1^, ptr2^, bmp1.Width*3);
  30.       end;
  31.  
  32.       bmp2.EndUpdate;
  33.       bmp2.SaveToFile('aa.bmp');
  34.  
  35.  
  36.     finally
  37.       bmp1.Free;
  38.       bmp2.Free;
  39.     end;
  40.   end;
  41. end;
  42.  

If you looked at the Rawimage.Description, you will notice the difference. The bitmap loaded has a bits per pixel of 24 while bitmap 2 has a bits per pixel of 32. While the depth of both bitmaps are 24bpp, the gtk widgetset internally prefers 4 bytes to store a pixel. therefore you cannot simply copy a whole line.

R1.Description:
Code: [Select]
 FORMAT = RICFRGBA,
  WIDTH = 480,
  HEIGHT = 360,
  DEPTH = 24,
  BITORDER = RIBOBITSINORDER,
  BYTEORDER = RIBOLSBFIRST,
  LINEORDER = RILOTOPTOBOTTOM,
  LINEEND = RILEDWORDBOUNDARY,
  BITSPERPIXEL = 24,
  REDPREC = 8,
  REDSHIFT = 16,
  GREENPREC = 8,
  GREENSHIFT = 8,
  BLUEPREC = 8,
  BLUESHIFT = 0,
  ALPHAPREC = 0,
  ALPHASHIFT = 0,
  MASKBITSPERPIXEL = 1,
  MASKSHIFT = 0,
  MASKLINEEND = RILEWORDBOUNDARY,
  MASKBITORDER = RIBOBITSINORDER,
  PALETTECOLORCOUNT = 0,
  PALETTEBITSPERINDEX = 0,
  PALETTESHIFT = 0,
  PALETTELINEEND = RILETIGHT,
  PALETTEBITORDER = RIBOBITSINORDER,
  PALETTEBYTEORDER = RIBOLSBFIRST

R2.Description:
Code: [Select]
 FORMAT = RICFRGBA,
  WIDTH = 480,
  HEIGHT = 360,
  DEPTH = 24,
  BITORDER = RIBOBITSINORDER,
  BYTEORDER = RIBOLSBFIRST,
  LINEORDER = RILOTOPTOBOTTOM,
  LINEEND = RILEDWORDBOUNDARY,
  BITSPERPIXEL = 32,
  REDPREC = 8,
  REDSHIFT = 16,
  GREENPREC = 8,
  GREENSHIFT = 8,
  BLUEPREC = 8,
  BLUESHIFT = 0,
  ALPHAPREC = 0,
  ALPHASHIFT = 0,
  MASKBITSPERPIXEL = 1,
  MASKSHIFT = 0,
  MASKLINEEND = RILEBYTEBOUNDARY,
  MASKBITORDER = RIBOBITSINORDER,
  PALETTECOLORCOUNT = 0,
  PALETTEBITSPERINDEX = 0,
  PALETTESHIFT = 0,
  PALETTELINEEND = RILETIGHT,
  PALETTEBITORDER = RIBOBITSINORDER,
  PALETTEBYTEORDER = RIBOLSBFIRST
« Last Edit: January 12, 2010, 01:09:51 am by Marc »
//--
{$I stdsig.inc}
//-I still can't read someones mind
//-Bugs reported here will be forgotten. Use the bug tracker

LuizAmérico

  • Sr. Member
  • ****
  • Posts: 458
Re: Different TBitmap.RawImage.Data behavior in Win32 and Linux
« Reply #19 on: January 12, 2010, 03:55:08 am »
I had the same problems some years ago.

With imaginglib this whould be done with few calls:

LoadImageFromFile(FileName, Data); // -> you get the image data
//after here you can work with Get/SetPixel32 independent of the data format

//to ensure a data format do more one call:
if Data.Format <> MyFormat then
  ConvertImage(Data, MyFormat);

You can use the Bits property to access directly the code. Here is one excerpt of a routine that masks a image data (FData) given a color. You can find good documentation in the site i mentioned earlier.

procedure TCairoImagingPicture.Mask(const AMaskColor: TColor24Rec; ClearAlpha: Boolean);
var
  Pixel: PColor32Rec;
  ByteCount: PtrUInt;
begin
  Pixel := FData.Bits;
  ByteCount := FData.Size shr 2;
  while ByteCount > 0 do
  begin
    //todo: optimize this comparation
    with Pixel^ do
    begin
      if (R = AMaskColor.R) and
        (G = AMaskColor.G) and
        (B = AMaskColor.B) then
        Color := $00000000
      else
        if ClearAlpha then
          A := 255;
    end;
    Inc(Pixel);
    Dec(ByteCount);
  end;
end;

dan59314

  • New Member
  • *
  • Posts: 38
Re: Different TBitmap.RawImage.Data behavior in Win32 and Linux
« Reply #20 on: January 12, 2010, 04:17:59 am »

Hi, Marc,
 
  I knew they are different in Description, but I still don't know how to make the soucecode work. I will try harder to see if I can figure it out.
 
  Btw, I got a stupid question. How you watch the TRawImage.Description, I never success on trace these information, and others. When I add it to watch dialog, it always show some kind of 'bmp2.RawImage.Description',  'A Syntax error in expression, near 'RawImage.Description'.

Daniel
« Last Edit: January 12, 2010, 04:25:03 am by dan59314 »

dan59314

  • New Member
  • *
  • Posts: 38
Re: Different TBitmap.RawImage.Data behavior in Win32 and Linux
« Reply #21 on: January 12, 2010, 04:31:52 am »
I had the same problems some years ago.

With imaginglib this whould be done with few calls:

LoadImageFromFile(FileName, Data); // -> you get the image data
//after here you can work with Get/SetPixel32 independent of the data format

//to ensure a data format do more one call:
if Data.Format <> MyFormat then
  ConvertImage(Data, MyFormat);

You can use the Bits property to access directly the code. Here is one excerpt of a routine that masks a image data (FData) given a color. You can find good documentation in the site i mentioned earlier.

procedure TCairoImagingPicture.Mask(const AMaskColor: TColor24Rec; ClearAlpha: Boolean);
var
  Pixel: PColor32Rec;
  ByteCount: PtrUInt;
begin
  Pixel := FData.Bits;
  ByteCount := FData.Size shr 2;
  while ByteCount > 0 do
  begin
    //todo: optimize this comparation
    with Pixel^ do
    begin
      if (R = AMaskColor.R) and
        (G = AMaskColor.G) and
        (B = AMaskColor.B) then
        Color := $00000000
      else
        if ClearAlpha then
          A := 255;
    end;
    Inc(Pixel);
    Dec(ByteCount);
  end;
end;


Hi, LuizAmerico,

  Where can I get imagingLib?

Daniel

LuizAmérico

  • Sr. Member
  • ****
  • Posts: 458

dan59314

  • New Member
  • *
  • Posts: 38
Re: Different TBitmap.RawImage.Data behavior in Win32 and Linux
« Reply #23 on: January 12, 2010, 05:53:59 am »
With this revised piece, I can now get better result, but mono.

       ptr1 := R1.Data + bmp1.Width*3*i;
        ptr2 := R2.Data + bmp2.Width*4*i;  //  make it increase every 4 byte

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




Code: [Select]
procedure TForm1.Button2Click(Sender: TObject);
var
  bmp1, bmp2:TBitmap;
  ptr1, ptr2:Pointer;
  i:integer;
  R1, R2: TRawImage;
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;

      R1 := bmp1.RawImage;
      bmp2.BeginUpdate;
      R2 := bmp2.RawImage;

      for i:=0 to bmp1.Height-1 do
      begin
        // something else since this won't work
        ptr1 := R1.Data + bmp1.Width*3*i;
        ptr2 := R2.Data + bmp2.Width*4*i;

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

        // The following should do the same thing, but became whole black.
        {(ptr2)^ :=  pByte(ptr1)^;
        pByte(ptr2+1)^ :=  pByte(ptr1+1)^;
        pByte(ptr2+2)^ :=  pByte(ptr1+2)^; }
      end;

      bmp2.EndUpdate;
      bmp2.SaveToFile('../cc.bmp');


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

And the weired one is
        (ptr2)^ :=  pByte(ptr1)^;
        pByte(ptr2+1)^ :=  pByte(ptr1+1)^;
        pByte(ptr2+2)^ :=  pByte(ptr1+2)^;

should same to Move(ptr1^, ptr2^, bmp1.Width*3);

but not.

I now know loaded bmp is 24 bit aligned, bmp2 is 32 bit aligned. I wonder the only problem now is I don't know how the RGB aligned in bmp2. Is it?

Daniel
« Last Edit: January 12, 2010, 05:57:59 am by dan59314 »

Marc

  • Administrator
  • Hero Member
  • *
  • Posts: 2510
Re: Different TBitmap.RawImage.Data behavior in Win32 and Linux
« Reply #24 on: January 12, 2010, 12:06:29 pm »
With this revised piece, I can now get better result, but mono.

       ptr1 := R1.Data + bmp1.Width*3*i;
       ptr2 := R2.Data + bmp2.Width*4*i;  //  make it increase every 4 byte
       Move(ptr1^, ptr2^, bmp1.Width*3);


this is because you are moving one line, but the pixels are wider. If you look how the colors are stored:
 
  bmp1: BGRBGRBGR
  bmp2: xBGRxBgrxBgr

so if you copy the 3 pixels above in one move, they are copied over the x

Quote
And the weired one is
        (ptr2)^ :=  pByte(ptr1)^;
        pByte(ptr2+1)^ :=  pByte(ptr1+1)^;
        pByte(ptr2+2)^ :=  pByte(ptr1+2)^;

should same to Move(ptr1^, ptr2^, bmp1.Width*3);

it is not the same. In the first case you only copy 1 pixel while with the move you copy "width" pixels
//--
{$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 #25 on: January 15, 2010, 01:55:39 am »
Quote


 bmp1: BGRBGRBGR
  bmp2: xBGRxBgrxBgr



And the weired one is
        (ptr2)^ :=  pByte(ptr1)^;
        pByte(ptr2+1)^ :=  pByte(ptr1+1)^;
        pByte(ptr2+2)^ :=  pByte(ptr1+2)^;

should same to Move(ptr1^, ptr2^, bmp1.Width*3);

it is not the same. In the first case you only copy 1 pixel while with the move you copy "width" pixels



Sorry, my mistake. I didn't notice that I only wrote one for-loop. I will revise it to double for-loop to mainpulate the single pixel each time.

  >>bmp1: BGRBGRBGR
  >>bmp2: xBGRxBgrxBgr


This is what I want to know, now I will know how to copy data by byte.

P.S. I can't watch the bmp.rawimage, description..... and most the variables. Can you show me how to watch them? That's why I can't trace to know.... bmp2: xBGRxBgrxBgr.


Thanks,

Daniel

dan59314

  • New Member
  • *
  • Posts: 38
Re: Different TBitmap.RawImage.Data behavior in Win32 and Linux
« Reply #26 on: January 15, 2010, 02:52:58 am »
Hi, Marc,

  I work it out. And the bmp2 should be aligned in BGRXBGRXBGRX or RGBXRGBX....., I am not sure since I can't watch the value.  X should be the last byte.

Code: [Select]
procedure TForm1.Button2Click(Sender: TObject);   
var
  bmp1, bmp2:TBitmap;
  ptr1, ptr2:Pointer;
  i,j:integer;
  R1, R2: TRawImage;
  strideBytes1, strideBytes2: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;

      R1 := bmp1.RawImage;
      bmp2.BeginUpdate;
      R2 := bmp2.RawImage;

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

        for j:=0 to bmp1.Width-1 do
        begin     

          Move(ptr1^,ptr2^, 3);

          ptr1 := Pointer( integer(ptr1)+3);   //BGRBGRBGR
          ptr2 := Pointer( integer(ptr2)+4);   //BGRXBGRXBGRX
        end;

      end;
      bmp2.EndUpdate;
      bmp2.SaveToFile('../cc.bmp');


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


Daniel

User137

  • Hero Member
  • *****
  • Posts: 1791
    • Nxpascal home
Re: Different TBitmap.RawImage.Data behavior in Win32 and Linux
« Reply #27 on: February 06, 2010, 04:14:58 pm »
As far as i see, RawImage has also palette and mask arrays but i don't know if you need them for exact result.

Also you make assumption that everything in data is in bytes which it isn't. Rawimage seems to support well images with pixels of even 7 bits or something. You can directly copy Raw data to another if you use RawImage.DataSize property instead of image width and height things.

I just yesterday made loading functions for OpenGL textures and gave small code hint there:
http://www.lazarus.freepascal.org/index.php/topic,7532.msg41410.html#msg41410

Marc

  • Administrator
  • Hero Member
  • *
  • Posts: 2510
Re: Different TBitmap.RawImage.Data behavior in Win32 and Linux
« Reply #28 on: February 18, 2010, 12:19:57 am »
Palette isn't used/implemented yet
//--
{$I stdsig.inc}
//-I still can't read someones mind
//-Bugs reported here will be forgotten. Use the bug tracker

 

TinyPortal © 2005-2018