Steven Landow Steven Landow - 15 days ago 6
Java Question

Which Canvas and Bitmap methods get scaled by dpi (Android)?

I know that android will automatically scale Bitmaps loaded from res/drawable by dpi. I manually shut that off with BitmapFactory options when I load the resources for my game, such as the tileset.

//Loads Bitmaps for the tileset
public void loadTiles(int s) {
Bitmap subimage = null;
BitmapFactory.Options o = new BitmapFactory.Options();
o.inScaled = false;
Bitmap tileset = BitmapFactory.decodeResource(activity.getResources(), s, o);
try {


numTilesAcross = tileset.getWidth() / tileSize;
tiles = new Tile[3][numTilesAcross];


for(int col = 0; col < numTilesAcross; col++) {
subimage = Bitmap.createBitmap(tileset,
col * tileSize,
0,
tileSize,
tileSize
);
tiles[0][col] = new Tile(subimage, Tile.UNBLOCKED);
subimage = Bitmap.createBitmap(tileset,
col * tileSize,
tileSize,
tileSize,
tileSize
);
tiles[1][col] = new Tile(subimage, Tile.BLOCKED);
subimage = Bitmap.createBitmap(tileset,
col * tileSize,
2 * tileSize,
tileSize,
tileSize
);
tiles[2][col] = new Tile(subimage, Tile.TRIGGER);
}

}
catch(Exception e) {
e.printStackTrace();
}
}


The problem is when I draw them to my Canvas (which is then drawn to a Surface View) if I test the game on any dpi lower than mdpi the tiles are scaled too small with space between, and if I test on anything higher they are drawn too big and overlap.

The main question is what methods scale using the dpi factor. I draw my images using

//tiles[r][c].getImage() returns a Bitmap
canvas.drawBitmap(
tiles[row][col].getImage(),
(int)x + col * tileSize,
(int)y + row * tileSize,
null
);


Does canvas.drawBitmap() scale using the dpi? Or is the scaling happening with the way I am getting subimages in my loadTiles(int s) method? I checked the width/height of the bitmaps loaded in loadTiles and they are the size I wanted.

NOTE: I am scaling the final image to the screen myself, size of all bitmaps drawn to the canvas should be dpi independent.

EDIT:
Here are some pictures of what is going on...
This is mdpi, it is how it is SUPPOSED to look
http://cdn.img42.com/e9359c298455d505c3317bd705372030.png

This is hdpi, notice how things are overscaled and overlap the tile drawn before them
http://cdn.img42.com/540b7896947049250fea3f3fa5a08331.png

This is ldpi, notice how the tiles are too small and they leave space inbetween
img42/420e938b3eebc503247cd0181b779402fe.png

Answer

I figured it out. I was reading the documentation for Canvas and I have to set the density on both the canvas AND the bitmaps when they are loaded by calling

canvas.setDensity(DisplayMetrics.DENSITY_MEDIUM);
bitmap.setDensity(DisplayMetrics.DENSITYMEDIUM);

Relevant Documentation:

https://developer.android.com/reference/android/graphics/Canvas.html#setDensity%28int%29

https://developer.android.com/reference/android/graphics/Bitmap.html#setDensity%28int%29

I also could just set all images pixel density back to the system pixel density after I load their subimages out of their sheets so that the game will look nicer and less scaled/skewed