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

#### RAW

• Hero Member
• Posts: 622
##### 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 FPC 3.0.4 // 1.7 FPC 3.1.1

#### circular

• Hero Member
• Posts: 2611
##### 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

• Hero Member
• Posts: 622
##### 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 FPC 3.0.4 // 1.7 FPC 3.1.1

#### circular

• Hero Member
• Posts: 2611
##### 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

• Hero Member
• Posts: 622
##### 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
5.    Blue    : BYTE;
6.    Green   : BYTE;
7.    Red     : BYTE;
8.    Reserved: BYTE
9.   end;
10.
11. var
12.   Row, Col: integer;
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: October 08, 2017, 02:30:11 am by RAW »
Windows 7 Pro (x64 Sp1) And Windows XP Pro (x86 Sp3) - LAZARUS 1.8 FPC 3.0.4 // 1.7 FPC 3.1.1

#### circular

• Hero Member
• Posts: 2611
##### 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