Unpremultiply 32 bit pixel buffer

Share your advanced PureBasic knowledge/code with the community.
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3942
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Unpremultiply 32 bit pixel buffer

Post by wilbert »

When I was trying to load some images using api functions, I noticed semi transparent images didn't look good and required an unpremultiply.

Here's a small module to premultiply and unpremultiply a 32 bit pixel buffer.

Code: Select all

DeclareModule Premultiply
  
  ; 32 bits RGBA or BGRA pixel buffer
  
  Declare PremultiplyPixels(*PixelBuffer32, NumPixels)
  Declare UnpremultiplyPixels(*PixelBuffer32, NumPixels)
  
EndDeclareModule

Module Premultiply
  
  EnableASM
  DisableDebugger
  
  CompilerIf #PB_Compiler_Processor = #PB_Processor_x86
    Macro rax : eax : EndMacro
    Macro rbx : ebx : EndMacro
    Macro rcx : ecx : EndMacro
    Macro rdx : edx : EndMacro
    Macro rsi : esi : EndMacro
  CompilerEndIf 
  
  Procedure PremultiplyPixels(*PixelBuffer32, NumPixels)
    lea rax, [premultiply.l_premultiplyTable]
    mov rdx, *PixelBuffer32
    mov rcx, NumPixels
    push rbx
    push rsi
    mov rsi, rax
    !premultiply.l_premul0:
    movzx eax, word [rdx + 2]
    cmp ah, 255
    !je premultiply.l_premul1
    movzx ebx, byte [rsi + rax]
    mov [rdx + 2], bl
    mov al, [rdx + 1]
    movzx ebx, byte [rsi + rax]
    mov [rdx + 1], bl
    mov al, [rdx]
    movzx ebx, byte [rsi + rax]
    mov [rdx], bl
    !premultiply.l_premul1:
    add rdx, 4
    sub rcx, 1
    !jnz premultiply.l_premul0
    pop rsi
    pop rbx    
  EndProcedure
  
  Procedure UnpremultiplyPixels(*PixelBuffer32, NumPixels)
    lea rax, [premultiply.l_premultiplyTable + 0x10000]
    mov rdx, *PixelBuffer32
    mov rcx, NumPixels
    push rbx
    push rsi
    mov rsi, rax
    !premultiply.l_unpremul0:
    movzx eax, word [rdx + 2]
    cmp ah, 255
    !je premultiply.l_unpremul1
    cmp ah, 0
    !je premultiply.l_unpremul1
    movzx ebx, byte [rsi + rax]
    mov [rdx + 2], bl
    mov al, [rdx + 1]
    movzx ebx, byte [rsi + rax]
    mov [rdx + 1], bl
    mov al, [rdx]
    movzx ebx, byte [rsi + rax]
    mov [rdx], bl
    !premultiply.l_unpremul1:
    add rdx, 4
    sub rcx, 1
    !jnz premultiply.l_unpremul0
    pop rsi
    pop rbx
  EndProcedure
  
  Procedure FillTable()
    lea rdx, [premultiply.l_premultiplyTable]
    push rbx
    mov ebx, 255
    sub ecx, ecx
    !premultiply.l_filltable0:
    movzx eax, ch
    mul cl
    add eax, 127
    div bl
    mov [rdx + rcx], al
    add cx, 1
    !jnz premultiply.l_filltable0
    add rdx, 0x10000
    mov ecx, 0x100
    sub bx, bx
    !premultiply.l_filltable1:
    mov eax, 255
    cmp cl, ch
    !jae premultiply.l_filltable2
    mul cl
    add ax, bx 
    div ch
    !premultiply.l_filltable2:
    mov [rdx + rcx], al
    add cl, 1
    !jnz premultiply.l_filltable1
    movzx bx, ch
    add bx, 1
    shr bx, 1
    add ch, 1
    !jnz premultiply.l_filltable1
    pop rbx
  EndProcedure
  
  FillTable()
  
  DataSection
    !premultiply.l_premultiplyTable: times 131072 db 0
  EndDataSection
  
EndModule
The way I used it is with this line of code for a 32 bit image

Code: Select all

Premultiply::UnpremultiplyPixels(DrawingBuffer(), (DrawingBufferPitch()*OutputHeight())>>2)
Last edited by wilbert on Wed Mar 23, 2016 1:25 pm, edited 2 times in total.
Windows (x64)
Raspberry Pi OS (Arm64)
User avatar
Keya
Addict
Addict
Posts: 1890
Joined: Thu Jun 04, 2015 7:10 am

Re: Unpremultiply 32 bit pixel buffer

Post by Keya »

very interesting! I hadnt even heard of it before but thats no surprise lol. I found this page helpful to get my head around it with these cool with/withouts:
Image
Image
User avatar
chi
Addict
Addict
Posts: 1087
Joined: Sat May 05, 2007 5:31 pm
Location: Austria

Re: Unpremultiply 32 bit pixel buffer

Post by chi »

Hey thanks! 3-4 times faster then

Code: Select all

Plot(x, y, RGBA( (255 * Red(color) + (Alpha(color) /2)) /alpha, (255 * Green(color) + (Alpha(color) /2)) /alpha, (255 * Blue(color) + (Alpha(color) /2)) /alpha, Alpha(color)))
Any chance on a PremultiplyPixels() procedure? :)

Code: Select all

Procedure PreMultiplyAlpha(image)
  StartDrawing(ImageOutput(image))
    DrawingMode(#PB_2DDrawing_AllChannels)
    For y=0 To ImageHeight(image)-1
      For x=0 To ImageWidth(image)-1
        color = Point(x, y)
        Plot(x, y, RGBA( (Red(color) * Alpha(color) + 127) /255, (Green(color) * Alpha(color) + 127) /255, (Blue(color) * Alpha(color) + 127) /255, Alpha(color)))
      Next
    Next
  StopDrawing()
  ProcedureReturn image
EndProcedure

Procedure UnPreMultiplyAlpha(image)
  StartDrawing(ImageOutput(image))
    DrawingMode(#PB_2DDrawing_AllChannels)
    For y=0 To ImageHeight(image)-1
      For x=0 To ImageWidth(image)-1
        color = Point(x, y)
        alpha = Alpha(color)
        If alpha=0 : alpha=1 : EndIf
        Plot(x, y, RGBA( (255 * Red(color) + (Alpha(color) /2)) /alpha, (255 * Green(color) + (Alpha(color) /2)) /alpha, (255 * Blue(color) + (Alpha(color) /2)) /alpha, Alpha(color)))
      Next
    Next
  StopDrawing()
  ProcedureReturn image
EndProcedure
[/size]
Et cetera is my worst enemy
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3942
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: Unpremultiply 32 bit pixel buffer

Post by wilbert »

chi wrote:Any chance on a PremultiplyPixels() procedure? :)
I made a few changes to my code.
- I added a premultiply procedure
- I made a few changes so it might be a bit faster
- I updated the code to a module so it doesn't interfere with other code

Please try and let me know if it makes a difference.
Windows (x64)
Raspberry Pi OS (Arm64)
User avatar
chi
Addict
Addict
Posts: 1087
Joined: Sat May 05, 2007 5:31 pm
Location: Austria

Re: Unpremultiply 32 bit pixel buffer

Post by chi »

I added a premultiply procedure
Thank you very much!
I made a few changes so it might be a bit faster
Dude, that's not funny anymore... I mean... HOW??? Unpremultiplying a 4k image takes about 6155ms with my code and only 10ms with yours. Yeah right, just a 'bit' faster ;). KUDOS
I updated the code to a module so it doesn't interfere with other code
Thanks again!
Et cetera is my worst enemy
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3942
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: Unpremultiply 32 bit pixel buffer

Post by wilbert »

chi wrote:Dude, that's not funny anymore... I mean... HOW??? Unpremultiplying a 4k image takes about 6155ms with my code and only 10ms with yours. Yeah right, just a 'bit' faster ;). KUDOS
Thanks :D
But are you sure you did your timings with the debugger disabled ? :wink: (otherwise they are not representable)
Windows (x64)
Raspberry Pi OS (Arm64)
User avatar
chi
Addict
Addict
Posts: 1087
Joined: Sat May 05, 2007 5:31 pm
Location: Austria

Re: Unpremultiply 32 bit pixel buffer

Post by chi »

Without debugger :oops:: 774ms / 10ms
Et cetera is my worst enemy
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3942
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: Unpremultiply 32 bit pixel buffer

Post by wilbert »

chi wrote:Without debugger :oops:: 774ms / 10ms
That sounds better.
Well, I'm still pleased with the difference :)
Windows (x64)
Raspberry Pi OS (Arm64)
User avatar
chi
Addict
Addict
Posts: 1087
Joined: Sat May 05, 2007 5:31 pm
Location: Austria

Re: Unpremultiply 32 bit pixel buffer

Post by chi »

Well, I'm still pleased with the difference :)
Me too! Thanks again...
Et cetera is my worst enemy
User avatar
chi
Addict
Addict
Posts: 1087
Joined: Sat May 05, 2007 5:31 pm
Location: Austria

Re: Unpremultiply 32 bit pixel buffer

Post by chi »

wilbert wrote:The way I used it is with this line of code for a 32 bit image

Code: Select all

Premultiply::UnpremultiplyPixels(DrawingBuffer(), DrawingBufferPitch()*OutputHeight()>>2)
should be...

Code: Select all

Premultiply::UnpremultiplyPixels(DrawingBuffer(), (DrawingBufferPitch()*OutputHeight())>>2)
#OperatorsPriorities
Et cetera is my worst enemy
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3942
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: Unpremultiply 32 bit pixel buffer

Post by wilbert »

You are right chi.
Thanks for mentioning :)
Windows (x64)
Raspberry Pi OS (Arm64)
Post Reply