ReadPixels Problem

Monkey Targets Forums/Android/ReadPixels Problem

Midimaster(Posted 2013) [#1]
A user of my game BallerBurg has a problem on his device. The castle looks wrong:



The device is a Samsung GT-S-5830i with Android 2.3.6.

The castle is a png with alpha transparency. To get a INT-array for manipulating it later I paint it on a fresh Cls screen, then immediately capture it back with this function:

Method GrabBurg:Void()
	Cls
	SetColor 255,255,255
	DrawImage BurgImage,0,0
	Original= New Int[240*240]
	ReadPixels(Original,0,0,240, 240,0)

	' recover Alpha 
	For Local i%=0 To 240*240-1
		If Original[i]=-16777216
			Original[i]=0
		Endif
	Next

	BurgImage = CreateImage(240,240)
	BurgImage.WritePixels(Original, 0, 0, 240,240)
End


Could it be that my idea of recovering the alpha, does not work on all devices, because the result of a "black pixel" is not always -16777216?


Nobuyuki(Posted 2013) [#2]
it's entirely possible. Sometimes textures are stored internally in 5-bit compressed format on certain devices to save space, and if I were to take an educated guess, this sorta thing can also affect matting knockout code that doesn't have a threshold greater than the banding amount. Was just looking at this crap today actually, for a module I'll be announcing soon....

Until then, maybe you can try using GetImagePixels to grab texture data directly instead?
http://monkeycoder.co.nz/Community/posts.php?topic=6087


AdamRedwoods(Posted 2013) [#3]
is it dithering? i suspect some devices force dithering if it is not specified. Monkey does not specify (targets/android/native/androidgame.java)
BitmapFactory.Options opts=new BitmapFactory.Options();
opts.inPreferredConfig=Bitmap.Config.ARGB_8888;
opts.inPurgeable=true;

we would need to add:
opts.inDither=false;



Gerry Quinn(Posted 2013) [#4]
Looks like dithering of some kind, you can see the pattern.

You could always include the alpha separately as a greyscale image.


Sub_Zero(Posted 2013) [#5]
Or split the Original[i] comparison into R,G and B as I did in this thread: http://www.monkeycoder.co.nz/Community/posts.php?topic=6209 and compare against a more than less than value... But this slows things down...


Gerry Quinn(Posted 2013) [#6]
You could find *approximately* black pixels quickly by using blackish:Bool = ( rgbVal & $00FEFEFE ) = 0, and only then do a more exact test.

[In point of fact, if dithering is involved that might be about as exact as you can get anyway...]


Midimaster(Posted 2013) [#7]
@nobuyuki
sorry, my english is not good enough... What do you mean with "...this sorta thing can also affect matting knockout code that doesn't have a threshold greater than the banding amount."

*** EDIT ****
The "no Dithering" workaround (AdamRedwoods) did not bring any improvement.


Nobuyuki(Posted 2013) [#8]
@Midimaster
It means that dithering could cause problems with the code you use to "knock out" the black color. If the threshold (wiggle amount) is lower than the amount of change created by dithering, then artifacts will still show through.

By the way... I released the module that I mentioned I would be announcing earlier. It has a few improvements over the other code I linked to. Perhaps it will work for you? (No HTML5 canvas support or Flash, unfortunately!) http://monkeycoder.co.nz/Community/posts.php?topic=7702


Midimaster(Posted 2013) [#9]
@Nobuyki

I could add your method of reading the pixel informations direct form the file. Thank you for that, it works. But there is a error message:
	Method GrabWithoutDither:Int[](FileName$)
               Local data:Int[], info%[2]
  		#If TARGET="android" 
                 Local db:DataBuffer = LoadImageData("monkey://data/" + FileName, info)
                Print "DATA BUFFER LENGTH= " + db.Length        
                Local timeSpent:Int = Millisecs()
                
                'Copy the data buffer into an array.
                 data = data.Resize(db.Length / 4) '32-bits = 4 bytes
        
                'We need to swap bytes of R and B channels around.
                For Local i:Int = 0 Until db.Length Step 4
                        Local j:Int = db.PeekInt(i)
                        
                        data[i / 4] = (j & $ff000000) | ((j & $00ff0000) Shr 16) | (j & $0000ff00) | ((j & $000000ff) Shl 16)
                Next
        
                Print "Operation took " + (Millisecs() -timeSpent) + "ms"
        #Endif        
		Return data
	End





Nobuyuki(Posted 2013) [#10]
You're getting nullpo but without the precompiled java code it is impossible to tell where exactly. Have you made sure to

1. wait until the first update loop to attempt to grab pixels?
2. wait until the surface is valid before rendering? (Updates and rendering occur asynchronously; you need a check to make sure the renderloop doesn't attempt to access a null surface)