Get the FULL version

Android: Disabling anti-aliasing for pixel art

Android: Disabling anti-aliasing for pixel art thumbnail

Android is great when it comes to displaying scaled pictures in applications and games since it tries to interpolate the pixels, making the resulting image look as good as possible. That works for almost every case, however, what about pixel art? This behavior isn’t good for that because, after scaling it, the resulting image will be “smoothed out”, invalidating the handcrafted pixel placement.

There are two options in this case: use an image with the correct size and never scale it, or try to disable anything that could be aliasing the image. This post is going to describe how to do the latter. As usual, an example project is available for download at the end of the post.

The first thing to do to avoid any kind of pixel alteration is to place your image inside all the three res/drawable density folders, like this:

Drawable folders screenshot.

The same image file named 'house.png', inside each of the drawable folders.

This ensures that, regardless of the device’s screen density, the image will always appear with the same number of pixels on the screen. The pixel art could even be scaled proportionally, and the pixels would stay exactly the same. However, this will make the image smaller at a high density screen and bigger if the image is being displayed at a low density one, but he pixels are left untouched. One thing that could be done to remedy that is to create one scaled image for each screen density, which could be necessary if the final physical size of the image on the screen has to stay the same.

Additionally, there are some things to watch out for in the code, when creating an application that uses pixel art images.  As an example, at a common Android application that uses a ImageView to display a image, just make sure that the code will make the image pixels remain the same, like this:

//get the image view from the XML file
ImageView iv = (ImageView)findViewById(R.id.iv_imageview);

//create a new Bitmap by decoding the image inside it
Bitmap bmp = BitmapFactory.decodeResource(this.getResources(), R.drawable.house);
//scale the bitmap proportionally
bmp = Bitmap.createScaledBitmap(bmp, bmp.getWidth()*2, bmp.getHeight()*2, false);

//set the Bitmap (bmp) to be displayed by the ImageView
iv.setImageBitmap(bmp);

Instead of attaching the whole code, the above is just what is necessary to scale the image without aliasing it. If you need a fully working example, you can download one at the end of the post. As it can be observed, the code creates a ImageView object and a Bitmap. The first is initialized from the XML file, and the second one is created from the ‘house.png‘ file ID (lines 2 and 5).

After that, at the 7th line, another Bitmap is created by calling the createScaledBitmap(), although it’s result is being stored at the same Bitmap object. It takes four parameters: a Bitmap; an Integer for the new width; another Integer for the height and most importantly, a boolean that flags whether this image should be anti-aliased.

Note that the first parameter is the bmp object, the second and the third are, respectively, the Bitmap’s width and height multiplied by two, and lastly, the anti-aliasing boolean is set to false.

The last line, sets the Bimap be displayed at the ImageView. Here’s a screenshot of the example application displaying the differences between an aliased and an anti-aliased image:

Image View Screenshot

The difference between setting the aliasing to true or false.

That should do for an application that uses the ImageView. When using the Canvas to draw the image to the screen, things are going to be a little different, as it can be seen on the following code:

package fortyonepost.com.pa;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.view.View;

public class CustomView extends View
{
	//creates a Bitmap object
	private Bitmap bitmap;
	//creates a Paint to set the render settings
	private Paint paint = new Paint();

	public CustomView(Context context)
	{
		super(context);

		//decode the image into the Bitmap
		bitmap = BitmapFactory.decodeResource(this.getResources(), R.drawable.house);

		//set the paint settings
		paint.setAntiAlias(false);
		paint.setDither(true);
		paint.setFilterBitmap(false);
	}

	@Override
	protected void onDraw(Canvas canvas)
	{
		//sets the background color to blue using hex ARGB values
		canvas.drawColor(0xFF00FFFF);
		//scale the Bitmap to be four times bigger than the original
		canvas.scale(4, 4);
		//render the bitmap at the specified position, using the paint object settings
		canvas.drawBitmap(bitmap, 5,5, paint);
		super.onDraw(canvas);
	}
}

The code starts by declaring a Bitmap and declaring and initializing a Paint object (lines 13 and 15). Next, inside the constructor, the Bitmap is initialized exactly the same way as the previous code (line 22).

Them comes the most important part of this View: the Paint object settings. The Paint object defines how a graphic element should be rendered on the screen. We can control some of these options by enabling/disabling some settings. For our pixel art image, anti-aliasing, dithering and filtering are disabled. This makes the image to be rendered as pixelated as possible (lines 25 through 27).

After that, inside the onDraw() method, the Bitmap is scaled to be four times larger them the original image (line 36), and it’s being rendered by the drawBitmap() method, that takes paint as one of its parameters (line 38). Here’s a screenshot of an Activity that uses the CustomView:

Example Application - Custom View Screenshot.

No harm done to the pixels, even if the image is rendered four times bigger than its original size.

Hopefully, this post is going to be useful to someone. As promised, here’s an example project with everything that was explained here:

Downloads

6 Comments to “Android: Disabling anti-aliasing for pixel art”

  1. Fred says:

    Thanks for this!

  2. Rotkaeqpchen says:

    I mailed this to Yongzh, he is the porter of Gameboid (GBA Emulator) for Android. I hope he will add this feature…

  3. kikijiki says:

    Thanks for the info!
    By the way, I think putting the image only once but in the “drawable” folder (without postfixes) should suffice.

    • kikijiki says:

      forgot to say, if you use only one copy of the image like I said, you should edit this line

      bitmap = BitmapFactory.decodeResource(this.getResources(), R.drawable.house);

      with

      BitmapFactory.Options options = new BitmapFactory.Options();
      options.inScaled = false;
      bitmap = BitmapFactory.decodeResource(this.getResources(), R.drawable.house, options);

  4. dude says:

    Thanks man, very helpful!

  5. TheDarkne55 says:

    Thanks a lot, that was explanatory and succint – really helped me out !

Leave a Reply to kikijiki

Post Comments RSS