How to use GetPixelData

508 views
Skip to first unread message

Michael Seymour

unread,
Jul 16, 2015, 7:41:12 AM7/16/15
to androi...@googlegroups.com
Hi! I've decided my next project (still working on my last project every now and then lol) is going to be an interface for a digital trading card game.

The full "card" images will be drawn onto a "board" image which is visible in the game, and a corresponding box of colour will be drawn on a hidden image, with a different colour per card. When I press or tap or swipe on the board, the game needs to know which card I'm interacting with, hence the hidden image with boxes of colour in place of cards. The boxes of colour may overlap in the same way the cards are overlapping in the game.

If the equivalent pixel I tap is green on the hidden image, then the game knows I've tapped a particular card, and likewise with red, blue, whatever colours I decide to use.

My question (or rather request) is a quick rundown of how I use GetPixelData to accomplish this or whether there's a better way of doing it. What kind of format does GetPixelData return? Could I reformat this into R, G, B values?
Thanks very much!

Chris Hopkin

unread,
Jul 16, 2015, 10:27:46 AM7/16/15
to androi...@googlegroups.com
Hi Michael

Sounds like an interesting new project. GetPixelData can give you the RGBA pixel data for all or part of an Image object. I posted the following function on another thread, it shows how you can turn the data returned by GetPixelData into an array of RGBA pixel objects: 

function GetPixels(image)
{
   
//Get the raw base64 encoded rgba string
   
var rawData = image.GetPixelData( "RawBase64" );

   
//Decode the base64 encoded string
   
var byteArray = atob( rawData );
   
   
//Convert the decoded byteArray into array of pixels objects
   
var pixels = [];
   
var byteIndex = 0;
   
while( byteIndex < byteArray.length )
   
{
       
var pixel = {};    
       pixel
.r = byteArray.charCodeAt(byteIndex++);
       pixel
.g = byteArray.charCodeAt(byteIndex++);
       pixel
.b = byteArray.charCodeAt(byteIndex++);
       pixel
.a = byteArray.charCodeAt(byteIndex++);
   
       pixels
.push(pixel);
   
}
 
   
return pixels;
}

If you are only ever dealing with rectangular objects, an alternative approach to consider might be to store an array of rectangle objects, representing the area each card image occupies. This array could be sorted from highest to lowest card, so when the user touches a card, you can iterate through the rectangle array to find the first rectangle that contains the touch x,y coordinates.

Either approach would be fine, but if you want more info/help with the seconds approach, let me know.

Thanks

Chris 

Steve Garman

unread,
Jul 17, 2015, 2:30:04 AM7/17/15
to androi...@googlegroups.com
The GetPixelData parameters left,top,width and height ought to be really useful here but I can't work out what units they use.

Does anyone know?

Also a hint on how to convert ev.X and ev.Y (from img_OnTouchDown) to the same units would be greatly appreciated.

Dave Smart

unread,
Jul 17, 2015, 5:09:04 AM7/17/15
to androi...@googlegroups.com
Hi Michael,

For this type of game, I think you might be better off using multiple image controls on an absolute layout.  You can then easily detect which object is touched.  You can position the images wherever you want on an absolute layout and also animate their movement using a library like tween.js.  If you leave a large enough transparent border around your png images, then you will also be able to rotate and skew the images too.

Regards
David

Chris Hopkin

unread,
Jul 17, 2015, 9:17:30 AM7/17/15
to androi...@googlegroups.com
Regarding your questions Steve,

The left, top, width, height parameters of GetPixelData are in pixels, based on the size of the original image (i.e. not the displayed size). It's worth noting that GetAbsWidth/Height return the pixel size of the displayed image, which may be scaled up or down from the original image size (depending on the width and height values you pass to CreateImage). So when using GetPixelData, you must work with the original image size, rather than the display size.

The ev.X and ev.Y touch coordinates are in the range 0 to 1, where (0,0) is the top-left of the image and (1,1) is the bottom-right. So to convert these coordinates to pixels, multiply the ev.X & ev.Y values by the pixel width & height of the image (again you must use the original image size if you intend to use them with GetPixelData).

Chris

Steve Garman

unread,
Jul 17, 2015, 9:27:05 AM7/17/15
to androi...@googlegroups.com
Thanks Chris,
So this works:


var txt;
//Called when application is started. 
function OnStart() 

    //Create a layout with objects vertically centered. 
    var lay = app.CreateLayout( "Linear", "FillXY" );     
     
    //Create a blank image. 
    var img = app.CreateImage( null, 0.8, 0.8 ); 
  img.SetOnTouchDown(img_OnTouchDown);
    lay.AddChild( img ); 

 txt=app.CreateText("WWWWWWWWW");
 lay.AddChild(txt);

    //Add layout to app.     
    app.AddLayout( lay ); 
     
    //Draw our picture. 
    DrawPicture(img); 


function DrawPicture(img) 

    //Fill image with solid white. 
    img.SetColor( "#ffffffff" ); 
     
    //Set drawing color to blue 
    //format is (#alpha:red:green:blue) in hex. 
    img.SetPaintColor( "#ff0000ff"  ); 
     
    //Draw a tiny point (single pixel) in 
    //the center of the image. 
    img.DrawPoint( 0.5, 0.5 ); 
         
    //Draw diagonal line. 
    img.SetLineWidth( 2.5 ); 
    img.SetPaintColor( "#ff0000ee"  ); 
    img.DrawLine( 0.6, 0.2, 0.7, 0.95 ); 
     
    //Draw circle with radius 0.1 of image width. 
    img.SetPaintColor( "#ff992299"  ); 
    img.DrawCircle( 0.2, 0.2, 0.1 ); 

    //Draw some red text. 
    img.SetTextSize( 24 ); 
    img.SetPaintColor( "#ffff0000"  ); 
    img.DrawText( "Hello World", 0.1, 0.8 ); 
     
    //Draw translucent rectangle. 
    img.SetPaintColor( "#22444444"  ); 
    img.DrawRectangle( 0.22, 0.7, 0.9, 0.88 ); 
     
    //Draw un-filled circle. 
    img.SetPaintStyle( "Line" ); 
    img.SetPaintColor( "#ff00aa00" ); 
    img.DrawCircle( 0.3, 0.5, 0.05 ); 


function img_OnTouchDown(ev)
{
   var color = getPixelColor(this,ev.X,ev.Y);
   txt.SetText(color);
}

function getPixelColor(img,x,y)
{
var ratio=app.GetScreenDensity()/160
var raw = img.GetPixelData( "RawBase64",
    x*img.GetAbsWidth(),
    y*img.GetAbsHeight(),1,1);
//Decode the base64 encoded string
var byteArray = atob(raw);
var r = byteArray.charCodeAt(0);
var g = byteArray.charCodeAt(1);
var b = byteArray.charCodeAt(2);
var a = byteArray.charCodeAt(3);
var col = "#" + toHex(a) + toHex(r) +toHex(g) + toHex(b);
return col;
}

//Return the 2 digit hex version of value, padded with
//leading zeros when required
function toHex(value)
{
    return ("00" + value.toString(16)).substr(-2);
}

Michael Seymour

unread,
Jul 18, 2015, 3:51:35 AM7/18/15
to androi...@googlegroups.com
Thankyou all! I have the array of pixel objects method to try, and I hadn't actually considered simply using moveable image controls. Both suggestions will give me plenty of fuel for thought and a springboard to start. Thanks again :-)

sankarshan dudhate

unread,
Jul 18, 2015, 9:48:46 AM7/18/15
to androi...@googlegroups.com
Sounds Great Project Michael. +1 for the idea

Steve Garman

unread,
Jul 18, 2015, 10:42:08 AM7/18/15
to androi...@googlegroups.com
I'd have probably done better to include a GetPixelColor example that uses a resized picture.

If anyone feels like cleaning up this sample, feel free to post a version of it on the wiki.


var txt,orig;
//Called when application is started. 
function OnStart() 

    //Create a layout with objects vertically centered. 
    var lay = app.CreateLayout( "Linear", "FillXY" );     
     
    //Create an image. 
    orig =  app.CreateImage( "/Sys/Img/Xylophone.png" );
    var img = app.CreateImage( "/Sys/Img/Xylophone.png",0.5,-1 ); 

    img.SetOnTouchDown(img_OnTouchDown);
    lay.AddChild( img ); 

 txt=app.CreateText("WWWWWWWWW");
 lay.AddChild(txt);

    //Add layout to app.     
    app.AddLayout( lay ); 
    


function img_OnTouchDown(ev)
{
   var color = getPixelColor(this,ev.X,ev.Y);
   txt.SetText(color);
}

function getPixelColor(img,x,y)
{

var raw = img.GetPixelData( "RawBase64",
    x*img.GetAbsWidth()*orig.GetWidth()/img.GetWidth(),
    y*img.GetAbsHeight()*orig.GetHeight()/img.GetHeight(),1,1);
//Decode the base64 encoded string
var byteArray = atob(raw);
if (byteArray.length < 4) return("?");
Reply all
Reply to author
Forward
0 new messages