Okay, this is quite simple to understand, but for some bizarre reason I can't get it working.. I've simplified this example from the actual code.
InputStream is = context.getResources().openRawResource(R.raw.someimage);
Bitmap bitmap = BitmapFactory.decodeStream(is);
try
{
int[] pixels = new int[32*32];
bitmap.getPixels(pixels, 0, 800, 0, 0, 32, 32);
}
catch(ArrayIndexOutOfBoundsException ex)
{
Log.e("testing", "ArrayIndexOutOfBoundsException", ex);
}
Why on earth do I keep getting an ArrayIndexOutOfBoundsException? the pixels array is 32x32 and as far as I'm aware I'm correctly using getPixels. The image dimensions is 800x800 and I am attempting to retrieve a 32x32 section. The image is a 32-bit PNG which is being reported as ARGB-8888.
Any ideas? even if I'm being an idiot! I'm about to throw the keyboard out of the window :D
use bitmap width as stride, in ur case 32
bitmap.getPixels(pixels, 0, 32, 0, 0, 32, 32);
every row gap with 800 causes ur pixelarray to get out of bound
"I'm about to throw the keyboard out of the window " funny lol
You're overflowing the destination buffer because you're asking for a stride of 800 entries between rows.
http://developer.android.com/reference/android/graphics/Bitmap.html#getPixels%28int[],%20int,%20int,%20int,%20int,%20int,%20int%29
You getting OutOfBounds exception becacuse stride is applied to pixels array not to the original bitmap,so in your case you're trying to retrieve 32*800 pixels which doesn't fit into your array.
Related
I have an image on which I want to process pixel number 159 and 160 specifically. I am running this code but it gives me ArrayIndexOutOfBoundsException. I think the way I have declared that array that is the problem.
int[] twoPositions = {159, 160};
bitmap.GetgetPixels(twoPositions, 0, width, 0, 0, width, height); //exception line (ArrayIndex....)
how to declare array in a way which will give me 0 row, 159th and 160th column pixel?
thank you in advance...
first the important lines of code:
Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), getDrawableForLvl(drawable));
int []pixels = new int[bitmap.getWidth()*bitmap.getHeight()];
bitmap.getPixels(pixels, 0, bitmap.getWidth(), 0, 0, bitmap.getWidth(), bitmap.getHeight());
//..
pixels = null; // please gc remove this huge data
System.gc();
So I'm working on an Android app (game) with multiple levels. Every level is an image that I load as bitmap on level start. Then I have to analyse every pixel (line 3). For that I create an array (line 2). The images are 1280x800, so the array has a size over one million ints. No problems here and since it's a local variable it should be destroyed on method return. But it's java, so it's not -.- Depending on the device the garbage collector is running fast enough in time or not. So when a user starts and closes levels very fast it produces a java.lang.OutOfMemoryError in line 2. I guess because the old array(s) wasn't/weren't removed yet and now I have multiple ones filling the memory.
I could make the array a static member. So it's created once and is always available. Then it's not possible to have multiple instances of it. But I think that's a bad coding style, because it's also available (4 MB) when not needed.
I don't need all pixels at the same time. I'm splitting the images in more than a hundred rectangles, so I could use a way smaller array and fill it one after another with pixels. But I have problems to understand the methods parameters can someone help me here?
There is also a method to get just one pixel at position x,y, but I guess a million function calls is pretty slow.
Has someone a better idea? There is no way to force an object out of memory in java, is there?
Update1:
As vzoha suggested to get only the first quarter:
int []pixels = new int[bitmap.getWidth()/2*bitmap.getHeight()/2];
bitmap.getPixels(pixels, 0, bitmap.getWidth(), 0, 0, bitmap.getWidth()/2, bitmap.getHeight()/2);
gives an ArrayIndexOutOfBound. I think the function call is just getting the pixels of the first quarter, but still expects the full size array and the other fields will be left untouched.
Update2: I guess I can do it row by row (half row by half row for the first quarter):
int []pixels = new int[bitmap.getWidth()/2*bitmap.getHeight()/2];
for(int row = 0; row < bitmap.getHeight()/2; ++row)
bitmap.getPixels(pixels, bitmap.getWidth()/2, bitmap.getWidth(), 0, row, bitmap.getWidth()/2, 1);
But when I do that for 20x10 parts it's not much better than getting each pixel by itself. Well it is much better but still the method should be capable to do that with one call, shouldn't it? I just don't get this "stride" parameter: "The number of entries in pixels[] to skip between rows (must be >= bitmap's width). Can be negative." How can it be negativ when >= width?
The size in pixels doesn't directly translate to how much memory the image will take up in memory. Bitmaps in Android (before using ART) are notoriously difficult to use heavily while avoiding OOM exceptions, enough so, that there's a page dedicated to how to use them efficiently. The problem is normally that there is actually enough memory available, but it has become fragmented and there isn't a single contiguous block the size you need available.
My first suggestion (for a quick win) would be to decode the bitmap with a specific config, you should be able to occupy only 1/4 of the amount of memory you were previously using by switching to use ALPHA_8 for your bitmap config. This will use 1 byte per pixel instead of 4 (the default is ARGB_8888)
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Bitmap.Config.ALPHA_8
bitmap = BitmapFactory.decodeResource(getResources(), getDrawableForLvl(drawable), options);
My next suggestion would be to scale you bitmap to start with and place the appropriate one in your hdpi,xhdpi,xxhdpi folders.
In fact it is pretty simple to get just the pixels of a specific area. But the documentation is wrong about the stride parameter. It says:
public void getPixels (int[] pixels, int offset, int stride, int x, int y, int width, int height)
stride: The number of entries in pixels[] to skip between rows (must be >= bitmap's width). Can be negative.
But the truth is it can (and must in most cases) be less than the bitmap's width, it just has to be bigger or equal to the passed width (the second to last parameter of getPixels), meaning the width of the area from which I want the pixels.
So to get the pixels of the first quarter of a bitmap:
int []pixels = new int[bitmap.getWidth()>>1 * bitmap.getHeight()>>1]; // quarter of the bitmap size
bitmap.getPixels(pixels, 0, bitmap.getWidth()>>1, 0, 0, bitmap.getWidth()>>1, bitmap.getHeight()>>1);
Or to get a specific rect with x,y (upper left corner) and width, height:
int []pixels = new int[width*height];
bitmap.getPixels(pixels, 0, width, x, y, width, height);
So pretty simple. It was just the wrong documentation that put a twist in my brain.
var targetSize = Math.max($(window).width(), $(window).height());
var canvas = $("#canvas")[0];
canvas.setAttribute('width', $(window).width());
canvas.setAttribute('height', $(window).height());
var context = canvas.getContext("2d");
var img = new Image(); // Create new img element
img.onload = function () {
angle = Math.PI / 4;
context.setTransform(1, 0, 0, 1, 0, 0); //attempt to reset transform
context.drawImage(img, 0, 0);
};
img.src = '../../Images/FloorPlans/GroundFloor.jpg'; // Set source path
This code produces the first image below on firefox17 on my nexus7. The original image is NOT angled, all of the lines should be north-south and east-west. It appears correctly on Firefox and chrome on the desktop, and chrome on my nexus7.
If i try to "un-skewer" the image using...
context.setTransform(1, 0, Math.tan(angle), 1, 0, 0);
I get the second output below! My target platform has to be FF on the Nexus7 :(
How can this be fixed? Or is this a firefox bug?
I've kinda worked it out.
The original image was a jpg, 1859px * 1568px ~ 501kb.
I resized it down to 50% and it worked! I then went back to the full size image (still not working) before resizing down 5% at a time. All of the images failed until I got to 75% of the original size (1394px * 1176px ~ 342kb) which worked perfectly!
So, the issue is either one of image size or file size.
Happy hunting!
UPDATE!
Thanks to Edward Falk's comment below, we have a definitive answer. Yes, shaving a single pixel of of the width of the image (thus making the width an even number of pixels) fixed the problem entirely.
Firefox canvas requires (some?) images to have an even pixel width and height, otherwise they may render incorrectly.
I've searched the web for help and although it looked like a solution it turned out to not work so good. For starters I'd like to say I've just jumped into android programming (this is my first day) I really learn by trial and error I'd like it that if you could help me you'd give me hints rather than paste the code in front of me.
my tileset
http://img217.imageshack.us/img217/4654/tileseth.png
the result
http://img199.imageshack.us/img199/7913/resultx.png
the issues I'm having is 1. it is obviously not splitting the image in 32 by 32 bits. is what I'm trying to achieve is take my big image and split it into 9* smaller images of 32 by 32 portions. Secondary the image quality gets distorted and I can't work out why.
*I don't want to use a 9 patch as there will be more then 9 images soon just a fluke that atm I have 9 images
my code (evidently plagiarized from the internet)
tilesetSliced = Bitmap.createScaledBitmap(bmp, 96, 96, true);
tileset[0] = Bitmap.createBitmap(tilesetSliced, 0, 0, 32, 32);
tileset[1] = Bitmap.createBitmap(tilesetSliced, 32, 0, 32, 32);
tileset[2] = Bitmap.createBitmap(tilesetSliced, 64, 0, 32, 32);
tileset[3] = Bitmap.createBitmap(tilesetSliced, 0, 32, 32, 32);
tileset[4] = Bitmap.createBitmap(tilesetSliced, 32, 32, 32, 32);
tileset[5] = Bitmap.createBitmap(tilesetSliced, 64, 32, 32, 32);
I'll make it more efficent once I got it working >.< any help would be great
the on draw
public void onDraw(Canvas canvas) {
//update();
for(int x=0; x<= mapWidth; x++){
for(int y = 0; y <= mapHeight; y++){
canvas.drawBitmap(tileset[map[x][y]], x *32, y*32, null);
}
}
}
o.k some more debugging has shead light on something 1. I removed the scaledbitmap that stopped the quality being destroyed (orginally ahd it due to bugs) however I found out that for some reason it thinks the width of my tileset is 64 when its 96 any help would be nice on this.
You may have more luck with a Bitmap Factory to generate your tilesetSliced. Within it is an Options class that allows you to set the sample size (inSampleSize) which can be used to scale down your image. It may not be precise enough for your needs, however.
Your images are likely distorted due to the scaling down process. Are you able to create these images with the right dimensions or pre-scale them?
I am trying to load a texture on to my android app display, where I am using code from this github.
I get my pixels messed up completely on the screen, And I have no idea, what's going on. The only thing I change in that code is I have memcpy, which copied uint8_t buffer into s_pixels instead of render_pixels in glbuffer.c file. My frame pixels are in rgb565 format.
Is it somekind of configuration problem or any problem with the way I copy pixels?
EDIT
Below is the code :
pictureQ is as below
pictureQ {
uint8_t *data;
int size;
}
memcpy(s_pixels,&(pictureQ[qFirst].data[0]) , 307200);
//render_pixels(s_pixels);
glClear(GL_COLOR_BUFFER_BIT);
// glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 480, 320, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, &(pictureRGBQ[qFirst].data[0]));
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 480, 320, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, s_pixels);
check_gl_error("glTexSubImage2D");
glDrawTexiOES(0, 0, 0, s_w, s_h);
check_gl_error("glDrawTexiOES");
memset(s_pixels, 0, 307200);
Ok, It was my mistake, I was passing the data for the pixels instead of the data. Thanks for your response Reuben Scatton.