Convert 24 / 32 bit pixels to 8 bit fixed palette
Posted: Sun Apr 14, 2013 5:41 pm
Here's a conversion routine I wrote to convert a number of pixels to an 8 bit fixed palette.
It requires SSE, is pretty fast, but since the palette is fixed the colors are more like those of an old computer
To test you would need to use one of your own images.
The test code simply converts an image to 8 bit and back again.
It requires SSE, is pretty fast, but since the palette is fixed the colors are more like those of an old computer

To test you would need to use one of your own images.
The test code simply converts an image to 8 bit and back again.
Code: Select all
Procedure Convert255(*OutputBuffer, *PixelData, NumPixels = 1, Mode = 3)
Protected reg_b.l
; mode 0 = 24 bit RGB
; mode 1 = 24 bit BGR
; mode 2 = 32 bit ARGB
; mode 3 = 32 bit ABGR
!mov ecx, [p.v_NumPixels]
!or ecx, ecx
!jz Conv255_Exit
CompilerIf #PB_Compiler_Processor = #PB_Processor_x86
!mov [p.v_reg_b], ebx
!mov ebx, [p.p_PixelData]
!mov edx, [p.p_OutputBuffer]
CompilerElse
!mov r8, [p.p_PixelData]
!mov r9, [p.p_OutputBuffer]
CompilerEndIf
!mov eax, [p.v_Mode]
!bt eax, 0
!jc Conv255_InitBGR
!movd mm1, [Conv255_Constants + 4]
!movd mm3, [Conv255_Constants + 8]
!jmp Conv255_InitDone
!Conv255_InitBGR:
!movd mm1, [Conv255_Constants + 12]
!movd mm3, [Conv255_Constants + 16]
!Conv255_InitDone:
!pxor mm4, mm4
!punpcklbw mm1, mm4
!movd mm2, [Conv255_Constants]
!punpcklbw mm2, mm4
!punpcklbw mm3, mm4
!bt eax, 1
!jnc Conv255_24bit_entry
; 32bit routine
!Conv255_32bit_loop:
CompilerIf #PB_Compiler_Processor = #PB_Processor_x86
!mov eax, [ebx]
!add ebx, 4
!call Conv255_Sub32
!mov [edx], al
!inc edx
!dec ecx
!jnz Conv255_32bit_loop
!mov ebx, [p.v_reg_b]
CompilerElse
!mov eax, [r8]
!add r8, 4
!call Conv255_Sub32
!mov [r9], al
!inc r9
!dec ecx
!jnz Conv255_32bit_loop
CompilerEndIf
!emms
!Conv255_Exit:
ProcedureReturn
; 24bit routine
!Conv255_24bit_loop:
CompilerIf #PB_Compiler_Processor = #PB_Processor_x86
!mov eax, [ebx]
!add ebx, 3
!call Conv255_Sub24
!mov [edx], al
!inc edx
!Conv255_24bit_entry:
!dec ecx
!jnz Conv255_24bit_loop
!mov ax, [ebx + 1]
!shl eax, 8
!mov al, [ebx]
!add ebx, 3
!call Conv255_Sub24
!mov [edx], al
!mov ebx, [p.v_reg_b]
CompilerElse
!mov eax, [r8]
!add r8, 3
!call Conv255_Sub24
!mov [r9], al
!inc r9
!Conv255_24bit_entry:
!dec ecx
!jnz Conv255_24bit_loop
!mov ax, [r8 + 1]
!shl eax, 8
!mov al, [r8]
!add r8, 3
!call Conv255_Sub24
!mov [r9], al
CompilerEndIf
!emms
ProcedureReturn
!Conv255_Sub32:
!bt eax, 31
!jc Conv255_Sub24
!mov eax, 0xfe
!ret
!Conv255_Sub24:
!movd mm0, eax
!punpcklbw mm0, mm4
!pshufw mm5, mm0, 01010101b
!psubw mm5, mm0
!pshufw mm5, mm5, 11101000b
!pmullw mm5, mm5
!movd eax, mm5
!pshufw mm0, mm0, 01100100b
!pmullw mm0, mm1
!paddw mm0, mm2
!and eax, 0xff00ff00
!jnz Conv255_Cont1
!psrlq mm0, 56
!movd eax, mm0
!cmp al, 0
!je Conv255_Cont2
!add al, 239
!cmp al, 254
!jne Conv255_Cont2
!mov al, 239
!ret
!Conv255_Cont1:
!psrlw mm0, 8
!pmullw mm0, mm3
!packuswb mm0, mm4
!psadbw mm0, mm4
!movd eax, mm0
!Conv255_Cont2:
!ret
!Conv255_Constants:
!dd 0x80808080; offset 0
!dd 0x0f030905; offset 4 (RGB constant 1)
!dd 0x00010428; offset 8 (RGB constant 2)
!dd 0x0f050903; offset 12 (BGR constant 1)
!dd 0x00280401; offset 16 (BGR constant 2)
EndProcedure
; calculate the palette that is used (6-10-4)
Dim Palette.l(254)
i = 0
For r = 0 To 5
For g = 0 To 9
For b = 0 To 3
Palette(i) = RGBA(r * 255 / 5, g * 255 / 9, b * 255 / 3, 255)
i + 1
Next
Next
Next
For i = 1 To 14
Palette(i + 239) = RGBA(i * 255 / 15, i * 255 / 15, i * 255 / 15, 255)
Next
; test the code
UsePNGImageDecoder()
LoadImage(0, "TestImage.png")
Width = ImageWidth(0)
Height = ImageHeight(0)
*Output = AllocateMemory(Width * Height)
StartDrawing(ImageOutput(0))
PixelFormat = DrawingBufferPixelFormat()
If PixelFormat & #PB_PixelFormat_24Bits_RGB
Mode = 0
ElseIf PixelFormat & #PB_PixelFormat_24Bits_BGR
Mode = 1
ElseIf PixelFormat & #PB_PixelFormat_32Bits_RGB
Mode = 2
Else
Mode = 3
EndIf
y = 0
*PixelData = DrawingBuffer()
Pitch = DrawingBufferPitch()
If PixelFormat & #PB_PixelFormat_ReversedY
While y < Height
Convert255(*Output + Width * (Height - y - 1), *PixelData + Pitch * y, Width, Mode)
y + 1
Wend
Else
While y < Height
Convert255(*Output + Width * y, *PixelData + Pitch * y, Width, Mode)
y + 1
Wend
EndIf
*IndexedPixels.Ascii = *Output
For y = 0 To Height - 1
For x = 0 To Width - 1
Plot(x, y, Palette(*IndexedPixels\a))
*IndexedPixels + 1
Next
Next
StopDrawing()
If OpenWindow(0, 0, 0, 600, 300, "Test", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
ImageGadget(0, 0, 0, 600, 300, ImageID(0))
Repeat : Until WaitWindowEvent() = #PB_Event_CloseWindow
EndIf