How to retrieve data as byte[] in GWT from getImageData

723 views
Skip to first unread message

Kevin Tarn

unread,
Feb 25, 2009, 11:45:26 AM2/25/09
to Google Web Toolkit
I have a canvas widget. I want to use JSNI to get canvas bitmap by
getImageData method. Is there a way to return getImageData output to
Java byte[]?

Kevin

Kevin Tarn

unread,
Feb 25, 2009, 1:49:05 PM2/25/09
to Google Web Toolkit
I have solved problem.

Kevin

Fabrício Cabral

unread,
Feb 28, 2009, 9:41:53 AM2/28/09
to Google-We...@googlegroups.com
Could you say how you solved this problem? For historic purpose...

Thanks in advance!

> I have solved problem.
>
> Kevin

--
--fx

Kevin Tarn

unread,
Mar 1, 2009, 7:52:43 PM3/1/09
to Google-We...@googlegroups.com
I got idea from canvas2image.js(http://www.nihilogic.dk/labs/canvas2image/). So I wrote a JSNI methods as below:

    public native String getImageData(int left, int top, int width, int height) /*-{

        var oData = this.@com.messenger.client.framework.Canvas::context.getImageData(left, top, width, height);

        var aImgData = oData.data;

    var strPixelData = "";
    var y = height;
        var iPadding = (4 - ((width * 3) % 4)) % 4;

    do {
            var iOffsetY = width*(y-1)*4;
            var strPixelRow = "";
            for (var x=0;x<width;x++) {
                    var iOffsetX = 4*x;

                    if (aImgData[iOffsetY+iOffsetX+2] == 0 &&
                        aImgData[iOffsetY+iOffsetX+1] == 0 &&
                        aImgData[iOffsetY+iOffsetX] == 0) {

                        strPixelRow += String.fromCharCode(255);
                        strPixelRow += String.fromCharCode(255);
                        strPixelRow += String.fromCharCode(255);
                    } else {
                        strPixelRow += String.fromCharCode(aImgData[iOffsetY+iOffsetX+2]);
                        strPixelRow += String.fromCharCode(aImgData[iOffsetY+iOffsetX+1]);
                        strPixelRow += String.fromCharCode(aImgData[iOffsetY+iOffsetX]);
                    }
            }
            for (var c=0;c<iPadding;c++) {
                    strPixelRow += String.fromCharCode(0);
            }
            strPixelData += strPixelRow;
        } while (--y);

        return strPixelData;
    }-*/;


As above method, I got a raw data in String object. So I need another method to convert it to byte array. Here it is:

    public byte[] getBitmap() {
        String str = getImageData(0, 0, width, height);
        byte[] ar = new byte[str.length()];
        for (int i=0; i<ar.length; i++)
            ar[i] = (byte)((int)str.charAt(i) & 0xff);
        return ar;
    }


Hope this is helpful.

Kevin

Kevin Tarn

unread,
Mar 1, 2009, 7:57:16 PM3/1/09
to Google-We...@googlegroups.com
Forgot to tell: getImageData method convert raw data to a Windows DIB format.

Kevin

Matt Bishop

unread,
Mar 3, 2009, 3:18:11 PM3/3/09
to Google Web Toolkit
This is pretty cool. You should try converting the data in GWT instead
of JSNI. It could go straight to bytes, or at least it could take
advantage of GWT's StringBuilder speed.


On Mar 1, 4:57 pm, Kevin Tarn <kevn.t...@gmail.com> wrote:
> Forgot to tell: getImageData method convert raw data to a Windows DIB
> format.
>
> Kevin
>
> On Mon, Mar 2, 2009 at 8:52 AM, Kevin Tarn <kevn.t...@gmail.com> wrote:
> > I got idea from canvas2image.js(http://www.nihilogic.dk/labs/canvas2image/).
> > So I wrote a JSNI methods as below:
>
> >     public native String getImageData(int left, int top, int width, int
> > height) /*-{
>
> >         var oData = th...@com.messenger.client.framework.Canvas::context.getImageData(left,

Kevin Tarn

unread,
Mar 3, 2009, 5:47:49 PM3/3/09
to Google-We...@googlegroups.com
Yes. That's what I like to do. Could you give an example of retreiving canvas raw data by GWT instead of JSNI?

Kevin

Thomas Broyer

unread,
Mar 3, 2009, 5:58:39 PM3/3/09
to Google Web Toolkit

On 3 mar, 23:47, Kevin Tarn <kevn.t...@gmail.com> wrote:
> Yes. That's what I like to do. Could you give an example of retreiving
> canvas raw data by GWT instead of JSNI?

Get our JSNI methods the shorter you can. Here, just make it get
oData.data and return it as a JsArrayNumber; then do all the following
in Java, with aImgData being the JsArrayNumber.
My guess is that you could turn it directly to bytes as the array
length could be computed early from width+height.

Kevin Tarn

unread,
Mar 4, 2009, 12:10:36 AM3/4/09
to Google-We...@googlegroups.com
Unfortunately, using JsArrayInteger is very slow:
    public byte[] getBitmap() {
//        String str = getImageData(0, 0, width, height);
//        byte[] ar = new byte[str.length()];
//        for (int i=0; i<ar.length; i++)
//            ar[i] = (byte)((int)str.charAt(i) & 0xff);
//        return ar;
         JsArrayInteger ja = getImageRawData(0, 0, width, height);
         int len = ja.length();
         byte[] ar = new byte[len];
         for (int i=0; i<len; i++)
             ar[i] = (byte)(ja.get(i) & 0xff);
         return ar;
    }

The loop above copying element to a byte array is 10 times above than the commented codes. Anything doing wrong?

Kevin

Thomas Broyer

unread,
Mar 4, 2009, 9:16:54 AM3/4/09
to Google Web Toolkit


On 4 mar, 06:10, Kevin Tarn <kevn.t...@gmail.com> wrote:
> Unfortunately, using JsArrayInteger is very slow:
>     public byte[] getBitmap() {
> //        String str = getImageData(0, 0, width, height);
> //        byte[] ar = new byte[str.length()];
> //        for (int i=0; i<ar.length; i++)
> //            ar[i] = (byte)((int)str.charAt(i) & 0xff);
> //        return ar;
>          JsArrayInteger ja = getImageRawData(0, 0, width, height);
>          int len = ja.length();
>          byte[] ar = new byte[len];
>          for (int i=0; i<len; i++)
>              ar[i] = (byte)(ja.get(i) & 0xff);
>          return ar;
>     }
>
> The loop above copying element to a byte array is 10 times above than the
> commented codes. Anything doing wrong?

If you're comparing runs in hosted mode, it doesn't really surprise
me, as JsArrayInteger will go back and forth from Java to JavaScript.
But once compiled into JS it should run (almost) at the same speed.

Now, it also depends how getImageRawData has been changed to return a
JsArrayInteger instead of a String...

Matt Bishop

unread,
Mar 4, 2009, 2:58:56 PM3/4/09
to Google Web Toolkit
According to the WhatWG spec for <canvas>, getImageData() returns a
CavasPixelArray, which is an array of bytes. What if you created a
JavaScriptObject to represent it? Does GWT thunk to bytes across the
JSNI boundary OK? I know it won't pass arrays of anything back, but
individual elements maybe:

import com.google.gwt.core.client.JavaScriptObject;

public class CanvasPixelArray extends JavaScriptObject {
protected CanvasPixelArray() {
//required by GWT
}

public native int getLength() /*-{
return this.length;
}-*/;

public native byte getPixelByte(int pos) /*-{
return this[pos];
}-*/;
}


//then, create one in your code:
public byte[] getBitmap(Element canvasElement, int left, int top, int
width, int height) {
//then, create one in your code:
CanvasPixelArray cpa = getCPA(canvasElement, left, top, width,
height);
byte[] pixelBytes = new byte[cpa.length()];
for (int i = 0; i < cpa.length(); i++) {
pixelBytes[i] = cpa.getPixelByte(i);
}
return pixelBytes;
}

private native CanvasPixelArray getCPA(Element canvas, int sx, int sy,
int sw, int sh) /*-{
return canvas.getContext("2d").getImageData(sx, sy, sw, sh);
}-*/;

Reply all
Reply to author
Forward
0 new messages