Dim bmc As BitmapCreator
Dim i As Int
Dim linePixels(128) As Int
Dim bc As ByteConverter
bmc.Initialize(128,1)
For i = 0 To 127
linePixels(i) = Colors.Red
Next
bc.LittleEndian = True
Bit.ArrayCopy(bc.IntsToBytes(linePixels),0,bmc.buffer,0,4*128)
XUIViewsUtils.SetBitmapAndFill(imgTest,bmc.Bitmap)
Then I display the image on a panel.
With Colors.Red, the image is Blue
With Colors.Green, the image is Green
With Colors.Blue, the image is Red
looks like Red and Blue corresponding bytes are reversed. This is a normal behavior?
The code is much more complex, I just provided a short example to reproduce the behavior.
I have to build the bitmap line by line (1024 pixels per line). SetColor per pixel is to slow, as the line of pixels is available as input data. Anyway, I suppose the behavior will be the same, as in my code I pass the color as an int too.
Looks like color representation as Colors.Red does not provide the expected color integer value for BitmapCreator.
Tried to change linePixels like that.
B4X:
For i = 0 To 127
k = i*255/127
linePixels(i) = k
Next
With LittleEndian = True, I get a gradient from Blue to Magenta from left to right. How can both red and blue can appear using an int from 0 to 255?
With LittleEndian = False, I get a gradient from Blue to Black from left to right. What is expected, right from left instead of left to right.
I seem to remember experiencing this in the early days of Android and B4A many years ago when doing low level bitmaps and expecting ARGB colours. Unfortunately I can't remember what the project was, nor the solution though it was probably just swap them as it seemed to work.
The android Bitmap format enumeration for full 8bit colour depth is
ANDROID_BITMAP_FORMAT_RGBA_8888
So it looks like maybe its little endian ABGR as you have found but maybe someone with better knowledge of Android graphics than I can shed more light.
I've no idea about the gradient without a project to play with to see it.
It was just as a simple example how color as an int is handled by BitmapCreator in B4A (different than in B4J).
In fact I have a 1024xYYY bitmap, where YYY can be any value between 100 and 1000.
The line of pixels is always 1024 in length, as input data (Ints array).
To be more specific, to behave the same:
In B4J: Color as Int is represented AARRGGBB, LittleEndian = True when converting Ints array to byte array
In B4A: Color as Int is represented RRGGBBAA, LittleEndian = False when converting Ints array to byte array
I don't have a working B4A setup here, but I've been mucking about in B4J with your sample code, and eventually I noticed that you have an array of 128 ints which is converted into an array of 512 bytes, but ArrayCopy is only copying the first 128 bytes. I added a multiply-by-four to the line:
I don't have a working B4A setup here, but I've been mucking about in B4J with your sample code, and eventually I noticed that you have an array of 128 ints which is converted into an array of 512 bytes, but ArrayCopy is only copying the first 128 bytes. I added a multiply-by-four to the line:
...
Is a typo in my example, as is manually reduced from what I have in my app.
Of course is 4x128. This not the issue. The issue is with the color int format required by BitmapCreator in B4A.
As written in my message, behavior in B4J is the expected one, so no issue at all in B4J. Only in B4A the format is different.
Is a typo in my example, as is manually reduced from what I have in my app.
Of course is 4x128. This not the issue. The issue is with the color int format required by BitmapCreator in B4A.
As written in my message, behavior in B4J is the expected one, so no issue at all in B4J. Only in B4A the format is different.
The pixel underlying format is different on different OS, in b4a a pixel byte order is RGBA, but b4j is BGRA ..., so you need convert color int to bytes according to different OS, as Erel said you'd better use built-in method to manipulate them as possible.
Reinstalled B4A, waited for development phone to download Android updates, tried this:
B4X:
For i = 0 To 127
#if b4a
'B4A under android: byte order is (R, G, B, A)
LinePixels(i) = bc.IntsFromBytes(Array As Byte(i, 0, 0, 255))(0)
#else
'B4J under windows: byte order is (B, G, R, A)
LinePixels(i) = bc.IntsFromBytes(Array As Byte(0, 0, i, 255))(0)
#end if
Next
with both B4J and B4A, seems to be working. But I think the conditional IntsFromBytes ordering is best put into a separate Sub rather than repeated throughout your code, which raises the question of... are we slowing sinking back to your original issue of:
Your code is just a solution for the minimal example provided by me in the first post (one color).
LinePixels is in my case an ints array (1024 in length) in the B4J format and is an input data, so I have to convert each pixel color independently.
On the other side, I didn't tried to see if SetPixel accept the right color format (as in B4J), not as when writing directly in BitmapCreator. If yes, Instead of calculating each pixel to build a new array and then copy the aray, I can use SetPixel directly in BitCreator. May be even faster.
I'm in the midst of timing it. Using SetARGB rather than SetColor. Got unbelievable times, then remembered that profiling in debug mode will get me a whack on the knuckles from you-know-who so now I'm trying to work out where #BridgeLogger belongs.
I forgot that in my app I build the linePixels using a palette array (byte to color). As I'm building the palette using the rule for B4A, SetPixels is no more required, nor efficient.
I can use directly ArrayCopy as it is now.
So the difference between B4A and B4J is just the way the palette array is built. And this is done one time only.
On the other side, I didn't tried to see if SetPixel accept the right color format (as in B4J), not as when writing directly in BitmapCreator. If yes ... I can use SetPixel directly in BitCreator. May be even faster.
Yeah, it'd be pretty disappointing if ARGBColor color channels weren't automatically configured to match the display.
B4X:
Private Sub B4XPage_Created (Root1 As B4XView)
Root = Root1
Root.LoadLayout("MainPage")
Dim bmc As BitmapCreator
Dim i As Int
Dim LinePixels(128) As Int
Dim bc As ByteConverter
bmc.Initialize(128, 1)
Dim TempARGB As ARGBColor
TempARGB.Initialize 'sets all to 0, including alpha (wth?)
TempARGB.a = 255
Log("Starting timing test")
Dim StartTime As Long = DateTime.Now
For ProfilingDoLots = 1 To 100000
For i = 0 To 127
TempARGB.r = i * 2
bmc.SetARGB(i, 0, TempARGB)
Next
Next
Dim EndTime As Long = DateTime.Now
Log("Finished timing test")
Log(((EndTime - StartTime) / 1000))
'''no longer needed - is already in bmc
'''Bit.ArrayCopy(bc.IntsToBytes(LinePixels), 0, bmc.buffer, 0, LinePixels.Length * 4)
XUIViewsUtils.SetBitmapAndFill(ImageView1, bmc.Bitmap)
End Sub
in Release Mode results in - for 100,000 x 128 pixel sets, and on a cheap-end phone too (I think AUD $70, definitely under $100) :
Not as I'm aware. I build the pallete as a Ints Array with 256 values. In fact initially the palette is a bitmap from where I extract the colors using GetPixel. The colors returned by GetPixel are the expected ones. I suppose SetPixel in BitmapCreator do the same, but as my problem is currently solved in an acceptable way, I will not further dig on this.