* * *

Author Topic: Make a transparent form with BGRABitmap  (Read 3103 times)

RAW

  • Sr. Member
  • ****
  • Posts: 488
Re: Make a transparent form with BGRABitmap
« Reply #15 on: July 17, 2017, 10:04:24 pm »
Thanks circular... obviously I need to learn something about graphics... asap...

It compiled very fine, but at runtime I get a SIGSEGV:
..exactly here:
Code: Pascal  [Select]
  1. If p^.alpha = 0

So I thought there must be something referred to "p", because if I use this line
Code: Pascal  [Select]
  1. p:= BGRA.Scanline[x];
then there is no error even if this is wrong...  :)


I thought I can use it like this: first precalculate and then premultiply...
Code: Pascal  [Select]
  1. Var
  2.  p: PBGRAPixel;
  3.  x, y: Integer;  
  4.  
  5. // precalculate bigger bitmap
  6. For x:= BGRA.Width-1 DownTo 0
  7. Do
  8.  Begin
  9.   If p^.alpha = 0
  10.   Then p^:= BGRAPixelTransparent
  11.   Else
  12.    Begin
  13.     p^.red  := p^.red  *(p^.alpha+1) SHR 8;
  14.     p^.green:= p^.green*(p^.alpha+1) SHR 8;
  15.     p^.blue := p^.blue *(p^.alpha+1) SHR 8;
  16.    End;
  17.   Inc(p);
  18.  End;
  19.  
  20. // premultiply bigger bitmap
  21. For y:= 0 To BGRA.Height-1
  22. Do
  23.  Begin
  24.   p:= BGRA.Scanline[y];
  25.  
  26.   For x:= BGRA.Width-1 DownTo 0
  27.   Do
  28.    Begin
  29.     p^.red  := p^.red  *p^.alpha Div 255;
  30.     p^.green:= p^.green*p^.alpha Div 255;
  31.     p^.blue := p^.blue *p^.alpha Div 255;
  32.     Inc(p);
  33.    End;
  34.  End;
Windows 7 Pro (x64 Sp1) And Windows XP Pro (x86 Sp3) - LAZARUS 1.8.0RC4 FPC 3.0.4

circular

  • Hero Member
  • *****
  • Posts: 2600
    • Personal webpage
Re: Make a transparent form with BGRABitmap
« Reply #16 on: July 17, 2017, 11:42:33 pm »
Oh ok maybe I did not express myself very well. Let's try again. I am not talking about precaculating, but about doing the computation as follows:
Code: Pascal  [Select]
  1.   For y:= 0 To PNG.Height-1 Do
  2.   Begin
  3.     p:= PNG.Scanline[y];
  4.     for x := PNG.Width-1 downto 0 do
  5.     begin
  6.       if p^.alpha = 0 then
  7.         p^ := BGRAPixelTransparent
  8.       else
  9.       begin
  10.         p^.red := p^.red*(p^.alpha+1) shr 8;
  11.         p^.green := p^.green*(p^.alpha+1) shr 8;
  12.         p^.blue := p^.blue*(p^.alpha+1) shr 8;
  13.       end;
  14.       inc(p);
  15.     end;
  16.   End;
  17.  

But of course, you could also do the precalculation using SHR and then applying it. That would avoid a multiply+SHR and use a memory access instead. Could be useful on a big picture.
Conscience is the debugger of the mind

RAW

  • Sr. Member
  • ****
  • Posts: 488
Re: Make a transparent form with BGRABitmap
« Reply #17 on: July 18, 2017, 12:45:23 am »
Ah, ok.. understood... thanks again.
Windows 7 Pro (x64 Sp1) And Windows XP Pro (x86 Sp3) - LAZARUS 1.8.0RC4 FPC 3.0.4

circular

  • Hero Member
  • *****
  • Posts: 2600
    • Personal webpage
Re: Make a transparent form with BGRABitmap
« Reply #18 on: July 18, 2017, 09:04:58 pm »
You're welcome.
Conscience is the debugger of the mind

RAW

  • Sr. Member
  • ****
  • Posts: 488
Re: Make a transparent form with BGRABitmap
« Reply #19 on: September 12, 2017, 10:21:09 pm »
I've played a little bit with premultiply procedures and it looks like precalculation is not necessary and in general I can't see really big differences...

AM+  = Anders Melander's version with precalculation
AM-  = Anders Melander's version without precalculation
CShr = Circular's Shr-version
CDiv = Circular's Div-version

Code: Pascal  [Select]
  1. JPG 1920 x 1200
  2.    AM+  AM-  CShr  CDiv
  3. 1.   0,  16,   0,    15 ms
  4. 2.   0,   0,  16,     0 ms
  5. 3.   0,   0,  15,     0 ms
  6.      
  7. JPG 2602 x 1734
  8.    AM+  AM-  CShr  CDiv
  9. 1.  16,  15,  16,    15 ms
  10. 2.  15,  16,   0,    16 ms
  11. 3.  16,   0,  16,    15 ms
  12.      
  13. JPG 8310 x 5500
  14.    AM+  AM-  CShr  CDiv
  15. 1. 156, 156, 141,   171 ms
  16. 2. 141, 140, 125,   156 ms
  17. 3. 140, 140, 110,   171 ms

Obviously when it comes to very big images then the CSHR-version is the best, but normally the pictures I use are a lot smaller so it doesn't matter what version, at least on my system and in this little test... funny...

And the winner is... CShr-version
Code: Pascal  [Select]
  1. Procedure PremultiplyBGRA(BMP: TBGRABitmap);
  2.   Var
  3.    iX, iY: Integer;
  4.    p: PBGRAPixel;
  5.  Begin
  6.   For iY:= 0 To BMP.Height-1
  7.   Do
  8.    Begin
  9.     p:= BMP.Scanline[iY];
  10.  
  11.     For iX:= BMP.Width-1 Downto 0
  12.     Do
  13.      Begin
  14.       If p^.Alpha = 0
  15.       Then p^:= BGRAPixelTransparent
  16.       Else
  17.        Begin
  18.         p^.Red  := p^.Red  *(p^.Alpha+1) SHR 8;
  19.         p^.Green:= p^.Green*(p^.Alpha+1) SHR 8;
  20.         p^.Blue := p^.Blue *(p^.Alpha+1) SHR 8;
  21.        End;
  22.       Inc(p);
  23.      End;
  24.    End;
  25.  End;

CDiv-version
Code: Pascal  [Select]
  1. Procedure PremultiplyBMP(BMP: TBGRABitmap);
  2.   Var
  3.    iX, iY: Integer;
  4.    p: PBGRAPixel;
  5.  Begin
  6.   For iY:= 0 To BMP.Height-1
  7.   Do
  8.    Begin
  9.     p:= BMP.Scanline[iY];
  10.  
  11.     For iX:= BMP.Width-1 DownTo 0
  12.     Do
  13.      Begin
  14.       p^.Red  := p^.Red  *p^.Alpha Div 255;
  15.       p^.Green:= p^.Green*p^.Alpha Div 255;
  16.       p^.Blue := p^.Blue *p^.Alpha Div 255;
  17.  
  18.       Inc(p);
  19.      End;
  20.    End;
  21.  End;

AM+ version
Code: Pascal  [Select]
  1. Procedure Premultiply(BMP: TBGRABitmap);
  2.   Var
  3.    iRow, iCol: Integer;
  4.    p: PBGRAPixel;
  5.    arrByte: Array[Byte, Byte] Of Byte;
  6.  Begin
  7.   For iRow:= 0 To 255
  8.   Do
  9.    For iCol:= iRow To 255
  10.    Do
  11.     Begin
  12.      arrByte[iRow, iCol]:= iRow*iCol Div 255;
  13.  
  14.      If (iRow <> iCol)
  15.      Then arrByte[iCol, iRow]:= arrByte[iRow, iCol];
  16.     End;
  17.  
  18.  
  19.   For iRow:= 0 To BMP.Height-1
  20.   Do
  21.    Begin
  22.     iCol:= BMP.Width;
  23.     p   := BMP.ScanLine[iRow];
  24.  
  25.     While (iCol > 0)
  26.     Do
  27.      Begin
  28.       p^.Blue := arrByte[p^.Alpha, p^.Blue];
  29.       p^.Green:= arrByte[p^.Alpha, p^.Green];
  30.       p^.Red  := arrByte[p^.Alpha, p^.Red];
  31.  
  32.       Inc(p);
  33.       Dec(iCol);
  34.      End;
  35.    End;
  36.  End;

AM original version
Code: Pascal  [Select]
  1. Procedure PremultiplyBitmap(Bitmap: TBitmap);
  2. type
  3.   pRGBQuad = ^TRGBQuad;
  4.   TRGBQuad = PACKED RECORD
  5.    Blue    : BYTE;
  6.    Green   : BYTE;
  7.    Red     : BYTE;
  8.    Reserved: BYTE
  9.   end;
  10.  
  11. var
  12.   Row, Col: integer;
  13.   p: PRGBQuad;
  14.   PreMult: array[byte, byte] of byte;
  15. begin
  16.   // precalculate all possible values of a*b
  17.   for Row := 0 to 255 do
  18.     for Col := Row to 255 do
  19.     begin
  20.       PreMult[Row, Col] := Row*Col div 255;
  21.       if (Row <> Col) then
  22.         PreMult[Col, Row] := PreMult[Row, Col]; // a*b = b*a
  23.     end;
  24.  
  25.   for Row := 0 to Bitmap.Height-1 do
  26.   begin
  27.     Col := Bitmap.Width;
  28.     p := Bitmap.ScanLine[Row];
  29.     while (Col > 0) do
  30.     begin
  31.       p^.Blue := PreMult[p^.Reserved, p^.Blue];
  32.       p^.Green := PreMult[p^.Reserved, p^.Green];
  33.       p^.Red := PreMult[p^.Reserved, p^.Red];
  34.       inc(p);
  35.       dec(Col);
  36.     end;
  37.   end;
  38. end;

Little test...
Code: Pascal  [Select]
  1. Procedure TForm1.Button1Click(Sender: TObject);
  2.   Var
  3.    cStart, cStop: Cardinal;
  4.    BGRA: TBGRABitmap;
  5.  Begin
  6.   BGRA:= TBGRABitmap.Create(Image2.Picture.Bitmap, False);
  7.    Try
  8.      cStart:= GetTickCount64;
  9.     PremultiplyCalc(BGRA);
  10.      cStop:= GetTickCount64-cStart;
  11.     Label1.Caption:= IntToStr(cStop);
  12.  
  13.      cStart:= GetTickCount64;
  14.     Premultiply(BGRA);
  15.      cStop:= GetTickCount64-cStart;
  16.     Label2.Caption:= IntToStr(cStop);
  17.  
  18.      cStart:= GetTickCount64;
  19.     PremultiplyBGRA(BGRA);
  20.      cStop:= GetTickCount64-cStart;
  21.     Label3.Caption:= IntToStr(cStop);
  22.  
  23.      cStart:= GetTickCount64;
  24.     PremultiplyBMP(BGRA);
  25.      cStop:= GetTickCount64-cStart;
  26.     Label4.Caption:= IntToStr(cStop);
  27.    Finally
  28.     BGRA.Free;
  29.    End;
  30.  End;
« Last Edit: September 19, 2017, 01:00:03 am by RAW »
Windows 7 Pro (x64 Sp1) And Windows XP Pro (x86 Sp3) - LAZARUS 1.8.0RC4 FPC 3.0.4

circular

  • Hero Member
  • *****
  • Posts: 2600
    • Personal webpage
Re: Make a transparent form with BGRABitmap
« Reply #20 on: September 18, 2017, 08:24:52 am »
Interesting. So MUL+SHR is faster than bidimensional array.
Conscience is the debugger of the mind

 

Recent

Get Lazarus at SourceForge.net. Fast, secure and Free Open Source software downloads Open Hub project report for Lazarus