Page 1 of 2
bitmap color fill
Posted: Wed Feb 24, 2021 11:28 pm
by chi
I stumbled upon an article on
codeproject.com and in the first code section there are some ASM instructions to fill a bitmap with a specific color. But all attempts porting it to PB ended with an IMA on "rep stosd". My knowledge about ASM is pretty limited, so it would be awesome if someone could guide me in the right direction
Code: Select all
lea rdi, BitmapData
mov rax, BitmapWidth
mov rcx, BitmapHeight
mul rcx
mov rcx, rax
mov rax, FillColor
rep stosd
[/size]
Re: bitmap color fill
Posted: Thu Feb 25, 2021 2:47 am
by Keya
what's an "IMA"?
"! rep stosd" compiles fine
but what worries me about this code, is that while it's very cute and compact (and I love it in that respect!) - but it assumes
perfect input data, it doesn't have any bounds/error-checking, which may be the cause of the problem.
We always have to be able to account for invalid/corrupt input data.
And for example, check out the BMP file format:
https://en.wikipedia.org/wiki/BMP_file_format
There is a field that defines "Extra bit masks" which is either 12 or 16 bytes. There's also other fields related to "structure alignment". I'm not saying that's the problem, but something the published code doesn't account for. eg is it a 32-bit BMP? 24-bit? 16-bit? 8-bit? 4-bit? 1-bit? im guessing your code is assuming 32bit
Re: bitmap color fill
Posted: Thu Feb 25, 2021 8:15 am
by infratec
IllegalMemoryAccess
You need the informations of DrawingBuffer() and DrawingBufferPitch()
Else you write to wrong locations.
And for 24bit you have to be very carefull, since it is stored with 3 bytes and not with 4.
Your assembler stuff stores 4 bytes.
Re: bitmap color fill
Posted: Thu Feb 25, 2021 10:04 am
by Mijikai
Example fills a bitmap with a 24 or 32-bit Color:
Code: Select all
EnableExplicit
Procedure.i BitmapFillColor(*Bits,Width.i,Height.i,Color.i,Depth.i = 32)
If *Bits And Width And Height
If Depth = 24
!mov rdi,[p.p_Bits]
!mov eax,dword[p.v_Color]
!mov rcx,[p.v_Width]
!imul rcx,0x3
!imul rcx,[p.v_Height]
!rep stosb
ProcedureReturn #True
ElseIf Depth = 32
!mov rdi,[p.p_Bits]
!mov eax,dword[p.v_Color]
!mov rcx,[p.v_Width]
!imul rcx,[p.v_Height]
!rep stosd
ProcedureReturn #True
EndIf
EndIf
ProcedureReturn #False
EndProcedure
Procedure.i Main()
Protected *bits
Protected w.i
Protected h.i
Protected s.i
If OpenConsole("")
w = 128
h = 64
PrintN("PRESS ANY KEY - 24 Bit Test!")
Input()
s = (w * 3) * h
*bits = AllocateMemory(s)
If *bits
BitmapFillColor(*bits,w,h,$FFFFFF,24)
ShowMemoryViewer(*bits,s)
FreeMemory(*bits)
EndIf
PrintN("PRESS ANY KEY - 32 Bit Test!")
Input()
s = (w * 4) * h
*bits = AllocateMemory(s)
If *bits
BitmapFillColor(*bits,w,h,$FFFFFFFF,32)
ShowMemoryViewer(*bits,s)
FreeMemory(*bits)
EndIf
Input()
CloseConsole()
EndIf
ProcedureReturn
EndProcedure
Main()
End
Re: bitmap color fill
Posted: Thu Feb 25, 2021 10:14 am
by wilbert
Mijikai wrote:Example fills a bitmap with a 24 or 32-bit Color:
This only works for 32 bit.
For 24 bit images you can only set a gray value from 0 - 255 but not a color.
Re: bitmap color fill
Posted: Thu Feb 25, 2021 10:29 am
by Mijikai
wilbert wrote:Mijikai wrote:Example fills a bitmap with a 24 or 32-bit Color:
This only works for 32 bit.
For 24 bit images you can only set a gray value from 0 - 255 but not a color.
Ups, since its a byte transfer...
I dont thing there is a neat solution then.
Re: bitmap color fill
Posted: Thu Feb 25, 2021 12:26 pm
by Helle
For instructions like STOSD it´s a good idea set/clear explicit the Direction Flag before. In this case
Code: Select all
...
!cld ;increment the index register
!stosd
Re: bitmap color fill
Posted: Thu Feb 25, 2021 2:21 pm
by chi
Thanks guys (especially Mijikai)! I might have a clue now what's going on here
wilbert wrote:Mijikai wrote:Example fills a bitmap with a 24 or 32-bit Color:
This only works for 32 bit.
For 24 bit images you can only set a gray value from 0 - 255 but not a color.
I only need 32-bit images, so the 24-bit stuff is not a problem.
Helle wrote:For instructions like STOSD it´s a good idea set/clear explicit the Direction Flag before. In this case
Code: Select all
...
!cld ;increment the index register
!stosd
[/size]Isn't the DF cleared on function entry anyways? It seems always set to 0.
This is what I'm going with...
Code: Select all
Procedure BitmapFillColor(Width.l, Height.l, ARGB.l=$FF000000)
Protected img.l, bmi.BITMAPINFO
bmi\bmiHeader\biSize = SizeOf(BITMAPINFOHEADER)
bmi\bmiHeader\biWidth = Width
bmi\bmiHeader\biHeight = -Height
bmi\bmiHeader\biPlanes = 1
bmi\bmiHeader\biBitCount = 32
img = CreateDIBSection_(0, @bmi, #DIB_RGB_COLORS, @*bits, 0, 0)
!mov edi,[p.p_bits]
!mov ecx,[p.v_Width]
!imul ecx,[p.v_Height]
!mov eax,[p.v_ARGB]
!cld
!rep stosd
ProcedureReturn img
EndProcedure
img.l = BitmapFillColor(300, 180, $FF00FF00)
OpenWindow(0, 0, 0, 320, 200, "", #PB_Window_SystemMenu|#PB_Window_ScreenCentered)
ImageGadget(0, 10, 10, 0, 0, img)
DeleteObject_(img)
While WaitWindowEvent() <> #PB_Event_CloseWindow : Wend
Re: bitmap color fill
Posted: Thu Feb 25, 2021 3:07 pm
by Mijikai
I fixed my code (thx Wilbert & Helle)
Now it works for 32 - 8 bit images:
Code: Select all
EnableExplicit
Procedure.i BitmapFillColor(*Bits,Width.i,Height.i,Color.i,Depth.i = 32)
If *Bits And Width And Height
If Depth = 32
!mov rdi,[p.p_Bits]
!mov eax,dword[p.v_Color]
!mov rcx,[p.v_Width]
!imul rcx,[p.v_Height]
!cld
!rep stosd
ProcedureReturn #True
ElseIf Depth > 7
!lea r8,[p.v_Color]
!mov r9,[p.p_Bits]
!mov rdx,[p.v_Depth]
!shr rdx,0x3
!mov rax,[p.v_Width]
!imul rax,[p.v_Height]
!cld
!@@:
!mov rsi,r8
!mov rdi,r9
!mov rcx,rdx
!rep movsb
!add r9,rdx
!dec rax
!test rax,rax
!jne @b
ProcedureReturn #True
EndIf
EndIf
ProcedureReturn #False
EndProcedure
Procedure.i Main()
Protected *bits
Protected w.i
Protected h.i
Protected s.i
If OpenConsole("")
w = 128
h = 64
PrintN("PRESS ANY KEY - 24 Bit Test!")
Input()
s = (w * 3) * h
*bits = AllocateMemory(s)
If *bits
BitmapFillColor(*bits,w,h,$332211,24)
ShowMemoryViewer(*bits,s)
FreeMemory(*bits)
EndIf
PrintN("PRESS ANY KEY - 32 Bit Test!")
Input()
s = (w * 4) * h
*bits = AllocateMemory(s)
If *bits
BitmapFillColor(*bits,w,h,$44332211,32)
ShowMemoryViewer(*bits,s)
FreeMemory(*bits)
EndIf
Input()
CloseConsole()
EndIf
ProcedureReturn
EndProcedure
Main()
End
Re: bitmap color fill
Posted: Thu Feb 25, 2021 3:37 pm
by Helle
@chi:
Code: Select all
Procedure BitmapFillColor(Width.l, Height.l, ARGB.l=$FF000000)
Protected img.l, bmi.BITMAPINFO
bmi\bmiHeader\biSize = SizeOf(BITMAPINFOHEADER)
bmi\bmiHeader\biWidth = Width
bmi\bmiHeader\biHeight = -Height
bmi\bmiHeader\biPlanes = 1
bmi\bmiHeader\biBitCount = 32
img = CreateDIBSection_(0, @bmi, #DIB_RGB_COLORS, @*bits, 0, 0)
CompilerIf #PB_Compiler_Processor = #PB_Processor_x86
!mov edi,[p.p_bits]
!mov ecx,[p.v_Width]
!imul ecx,[p.v_Height]
!mov eax,[p.v_ARGB]
;!cld
!rep stosd
CompilerElse
!mov rdi,[p.p_bits]
!mov rcx,[p.v_Width]
!imul rcx,[p.v_Height]
!mov rax,[p.v_ARGB]
;!cld
!rep stosd
CompilerEndIf
ProcedureReturn img
EndProcedure
;...
!std ;e.g. from another part of your program (und du suchst dich dumm und dämlich :-) )
;...
img = BitmapFillColor(300, 180, $FF00FF00)
OpenWindow(0, 0, 0, 320, 200, "", #PB_Window_SystemMenu|#PB_Window_ScreenCentered)
ImageGadget(0, 10, 10, 0, 0, img)
While WaitWindowEvent() <> #PB_Event_CloseWindow : Wend
DeleteObject_(img)
Re: bitmap color fill
Posted: Thu Feb 25, 2021 4:34 pm
by chi
@Helle: Oh, OK... Guess I have a lot to learn. Thanks for the clarification!
@Mijikai: Is there a reason why you use
[/size] instead of
[/size]Something I should be aware of?
Re: bitmap color fill
Posted: Thu Feb 25, 2021 6:16 pm
by Mijikai
chi wrote:
@Mijikai: Is there a reason why you use
[/size] instead of
[/size]Something I should be aware of?
It results in smaller code.
Re: bitmap color fill
Posted: Fri Feb 26, 2021 5:28 am
by chi
Mijikai wrote:It results in smaller code.
Actually I "learned" that a few month ago, but I already forgot

. Thanks for the reminder ^^
Re: bitmap color fill
Posted: Sat Feb 27, 2021 12:24 pm
by Olli
All this could be considered useless !
Box() is as fast and short !
However
This code above is useful, not having native equivalent. This scans (searches) a RGBA color. And this uses the same general registers (and direction flag) to process. So...
This is no so useless !
Just be careful with the direction flag :
He must be always set to decreasing status, after the ASM routine, else you will crash PureBasic !
And to search a primary color (red, green, blue or alpha value), an optimum (minimum or maximum color value), or to set to gray (or grey if Shakespeare wants it, by calculating the colors distances), AVX ASM statements are required.
Re: bitmap color fill
Posted: Sat Feb 27, 2021 1:30 pm
by Mijikai
Olli wrote:All this could be considered useless !
Box() is as fast and short !
Its useable if you can accept all the limitations that come with it.
The Box() command requires the creation of a device context and the allocation of additional memory.
All that is not needed here.