alex czernenk alex czernenk - 2 months ago 17
Android Question

Resource Intensive code fix

I have the following piece of code running on a picture. It produces the following error. I am assuming it is because the code takes a few seconds to run and then crashes so must be too much for the cpu to handle. I would like to ask how would I modify this code so it completes in <1second and is less intensive and so it doesnt crash. Thanks. Alex

E/AndroidRuntime: FATAL EXCEPTION: main
Process: cartoonify.alexcz.cartoonify, PID: 25764
java.lang.IllegalStateException
at android.graphics.Bitmap.setPixels(Bitmap.java:1626)
at cartoonify.alexcz.cartoonify.Main$2.onClick(Main.java:111)





change_pic.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if(picturePresent == true){

int r,g,b,colour;

int [] allpixels = new int [picture.getHeight() * picture.getWidth()];

picture.getPixels(allpixels, 0, picture.getWidth(), 0, 0, picture.getWidth(), picture.getHeight());

for(int i = 0; i < allpixels.length; i++)
{
colour = allpixels[i];
r = Color.red(colour);
b = Color.blue(colour);
g = Color.green(colour);

if(r < FIRSTSECTION){
r = FIRST;
}else if(r >= SECONDSECTION && r < THIRDSECTION){
r = SECOND;
}else if(r >= THIRDSECTION && r < FOURTHSECTION){
r = THIRD;
}else if(r >= FOURTHSECTION && r < FIFTHSECTION){
r = FORTH;
}

if(b < FIRSTSECTION){
b = FIRST;
}else if(b >= SECONDSECTION && b < THIRDSECTION){
b = SECOND;
}else if(b >= THIRDSECTION && b < FOURTHSECTION){
b = THIRD;
}else if(b >= FOURTHSECTION && b < FIFTHSECTION){
b = FORTH;
}

if(g < FIRSTSECTION){
g = FIRST;
}else if(g >= SECONDSECTION && g < THIRDSECTION){
g = SECOND;
}else if(g >= THIRDSECTION && g < FOURTHSECTION){
g = THIRD;
}else if(g >= FOURTHSECTION && g < FIFTHSECTION){
g = FORTH;
}

allpixels[i] = Color.argb(1, r, g, b);

}

picture.setPixels(allpixels, 0, picture.getWidth(), 0, 0, picture.getWidth(), picture.getHeight());
drawableBitmap = new BitmapDrawable(getResources(), picture);
image.setBackground(drawableBitmap);
}
}
});

Answer

setPixels requires a mutable Bitmap, otherwise you will get an IllegalStateException. See documentation.

You should copy or create a new bitmap, and make it mutable:

To create a new mutable bitmap:

Bitmap newBitmap = Bitmap.createBitmap(originalWidth, originalHeight, Bitmap.Config.ARGB_8888);

Or to copy and make a mutable bitmap:

boolean isMutable = true;
Bitmap newBitmap = originalBitmap.copy(Bitmap.Config.ARGB_8888, isMutable);

Now you will be able to use newBitmap.setPixels(...)

If this is an expensive operation, you should consider doing it in a background thread (e.g. AsyncTask).