Page 1 of 1

Unpremultiply 32 bit pixel buffer

Posted: Mon Mar 14, 2016 8:44 pm
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)

Re: Unpremultiply 32 bit pixel buffer

Posted: Mon Mar 14, 2016 9:44 pm
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

Re: Unpremultiply 32 bit pixel buffer

Posted: Tue Mar 15, 2016 1:13 am
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]

Re: Unpremultiply 32 bit pixel buffer

Posted: Tue Mar 15, 2016 6:31 am
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.

Re: Unpremultiply 32 bit pixel buffer

Posted: Tue Mar 15, 2016 2:44 pm
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!

Re: Unpremultiply 32 bit pixel buffer

Posted: Tue Mar 15, 2016 2:53 pm
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)

Re: Unpremultiply 32 bit pixel buffer

Posted: Tue Mar 15, 2016 3:23 pm
by chi
Without debugger :oops:: 774ms / 10ms

Re: Unpremultiply 32 bit pixel buffer

Posted: Tue Mar 15, 2016 3:25 pm
by wilbert
chi wrote:Without debugger :oops:: 774ms / 10ms
That sounds better.
Well, I'm still pleased with the difference :)

Re: Unpremultiply 32 bit pixel buffer

Posted: Tue Mar 15, 2016 3:26 pm
by chi
Well, I'm still pleased with the difference :)
Me too! Thanks again...

Re: Unpremultiply 32 bit pixel buffer

Posted: Wed Mar 23, 2016 12:33 pm
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

Re: Unpremultiply 32 bit pixel buffer

Posted: Wed Mar 23, 2016 1:26 pm
by wilbert
You are right chi.
Thanks for mentioning :)