Recent

Author Topic: Raw Image Structure (BGRA) to TBitmap - Fastest way  (Read 460 times)

gabriemarcelo

  • New Member
  • *
  • Posts: 28
Raw Image Structure (BGRA) to TBitmap - Fastest way
« on: September 04, 2019, 03:05:35 pm »
Hi guys... Lets say that I have a raw image structure in memory where each pixel is stored in BGRA (4 bytes per pixel). I can get the pointer to that buffer. I need to print or draw it on a Canvas. To draw that raw image, I create a TBitmap with the same Width & Height and then loop through each raw pixel BGRA values and set it to the TBitmap. A snipped code is below... My question is... can I avoid looping through the raw structure and instead just set the new TBitmap.RawImage.Data to that pointer? I'd like to avoid creating two buffers in order to I need to speed up this code... any hints on this? thanks in advance

Code: Pascal  [Select]
  1.  
  2. // bmpPage is the BGRA structure in memory...
  3.  
  4. bmp := TBitmap.Create;
  5. bmp.Width := bmpPage.Width;
  6. bmp.Height := bmpPage.Height;
  7.  
  8. bmp.BeginUpdate();
  9.  
  10. bytesPerPixel := bmp.RawImage.Description.BitsPerPixel div 8;
  11. redOffset := bmp.RawImage.Description.RedShift div 8;
  12. greenOffset := bmp.RawImage.Description.GreenShift div 8;
  13. blueOffset := bmp.RawImage.Description.BlueShift div 8;
  14.  
  15. ptr := bmpPage.GetBuffer;
  16.  
  17. for Y := 0 to bmp.Height - 1 do
  18. begin
  19.         LinePixs := bmp.RawImage.GetLineStart(Y);
  20.         for X := 0 to bmp.Width - 1 do
  21.         begin
  22.                 b := PByte(ptr)^;
  23.                 inc(ptr);
  24.                 g := PByte(ptr)^;
  25.                 inc(ptr);
  26.                 r := PByte(ptr)^;
  27.                 inc(ptr);
  28.                 a := PByte(ptr)^;
  29.                 inc(ptr);
  30.  
  31.                 (LinePixs+blueOffset)^ := b;
  32.                 (LinePixs+greenOffset)^ := g;
  33.                 (LinePixs+redOffset)^ := r;
  34.                 inc(LinePixs, bytesPerPixel);
  35.         end;
  36. end;
  37.  
  38. bmp.EndUpdate();  
  39.        
  40.  
« Last Edit: September 05, 2019, 12:59:20 pm by gabriemarcelo »

BeanzMaster

  • Full Member
  • ***
  • Posts: 182
Re: Raw Image Structure (BGRA) to TBitmap - Fastest way
« Reply #1 on: September 05, 2019, 06:10:08 pm »
Hi, this is the method i'm using in my library

Code: Pascal  [Select]
  1. function TBZCustomBitmap.ExportToBitmap : Graphics.TBitmap;
  2. var
  3.   Temp:     Graphics.TBitmap;
  4.   RawImage: TRawImage;
  5.   BitmapHandle, MaskHandle: HBitmap;
  6.   W,H : Integer;
  7.   Buffer : PByte;
  8. Begin
  9.   result := nil;
  10.   BitmapHandle := 0;
  11.   MaskHandle := 0;
  12.   w := Self.Width;
  13.   h:=  Self.Height;
  14.   Buffer := PByte(GetSurfaceBuffer);
  15.  
  16.   RawImage.Init;
  17.   RawImage.Description.Init_BPP32_R8G8B8A8_BIO_TTB(W,H);
  18.   RawImage.Data := Buffer;
  19.   RawImage.DataSize:= Self.Size;
  20.  
  21.   if not RawImage_CreateBitmaps(RawImage, BitmapHandle, MaskHandle, False) then
  22.   begin
  23.     raise EBZBitmapException.Create('Failed to create bitmap handle');
  24.   end
  25.   else
  26.   begin
  27.    Temp := Graphics.TBitmap.Create;
  28.    Temp.Handle := BitmapHandle;
  29.    Temp.MaskHandle := MaskHandle;
  30.    Result := Temp;
  31.   end;
  32.   if (Result=nil) then Raise EBZBitmapException.Create('Erreur de conversion vers TBitmap');
  33. End;

"GetSurfaceBuffer" return my raw buffer in (bgra or rgba format depend the os)

Cheers

gabriemarcelo

  • New Member
  • *
  • Posts: 28
Re: Raw Image Structure (BGRA) to TBitmap - Fastest way
« Reply #2 on: September 05, 2019, 11:47:40 pm »
thanks for sharing the code. I tested it but it does not work as expected because my raw image format is BGRA and your code assumes it's RGBA as in your code you call Init_BPP32_R8G8B8A8_BIO_TTB
The code runs but the output image has wrong pixel values as expected because again, my source is BGRA.

If I change that call to this one (which should be the correct for BGRA format)  Init_BPP32_B8G8R8A8_M1_BIO_TTB then the code fails at that procedure (error Image attached).

Do you know why?

BeanzMaster

  • Full Member
  • ***
  • Posts: 182
Re: Raw Image Structure (BGRA) to TBitmap - Fastest way
« Reply #3 on: September 06, 2019, 08:13:55 pm »
Hi,

in your code Size is incorrect. It's (w*h) *4 (4 is for BGRA or RGBA. One byte per channel  ;)) so try an tell us
And also becarefull with your "Buffer" it must be a PByte. I don't known what is your structure exactly.

Cheers


gabriemarcelo

  • New Member
  • *
  • Posts: 28
Re: Raw Image Structure (BGRA) to TBitmap - Fastest way
« Reply #4 on: September 06, 2019, 09:28:57 pm »
That did the trick! Thanks a lot. Regards,

gabriemarcelo

  • New Member
  • *
  • Posts: 28
Re: Raw Image Structure (BGRA) to TBitmap - Fastest way
« Reply #5 on: September 06, 2019, 11:36:57 pm »
Bad news... the code fails in macOS compiling to Cocoa 64bit apps... the code fails in the RawImage_CreateBitmaps (in the cocoalclintf.inc) more precisely in the RawImage_DescriptionToBitmapType which is not implemented for BGRA as it's not listed in the TCocoaBitmapType :( ... Did you test your code in macOS cocoa?

BeanzMaster

  • Full Member
  • ***
  • Posts: 182
Re: Raw Image Structure (BGRA) to TBitmap - Fastest way
« Reply #6 on: September 09, 2019, 09:13:07 pm »
Hi, sorry ,i can't test actually with Mac and don't know how Cocoa64 scheme. But perhaps the trick will be to create an RGBA raw image, and so you'll must swap R&B of your buffer before export it.

This how i swap R&B

Code: Pascal  [Select]
  1. // Fast Red-Blue channel color swapping
  2. Type
  3.   TBZColor =record // Very simplified record of my solution
  4.   Case Integer of
  5.      //0 : (Red, Green, Blue, Alpha : Byte); For Linux, Mac and other
  6.      0 : (Blue, Green, Red, Alpha : Byte); //For Windows
  7.      1 : (AsInteger : Cardina)l;
  8.   end;
  9.  
  10.   PBZColor = ^TBZColor;
  11.  
  12.   procedure SwapRB(Buf: PBZColor; pixelCount: Integer);
  13.   var
  14.     Pixptr: PBZColor;
  15.     AIntColor : Cardinal;
  16.   begin
  17.     PixPtr := Buf;
  18.     while pixelCount > 0 do
  19.     begin
  20.       AIntColor := PixPtr^.AsInteger;
  21.       PixPtr^.AsInteger := AIntColor and $FF00FF00 or (AintColor and $000000FF SHL 16) or (AIntColor and $00FF0000 SHR 16);
  22.       Inc(PixPtr);
  23.       Dec(pixelCount);
  24.     end;
  25.   end;