Reputation: 23018
In a simple word game app I load 26 letter tile images from a PNG-image stripe with the following code:
private static final CharacterIterator ABC =
new StringCharacterIterator("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
private static HashMap<Character, Bitmap> sImages =
new HashMap<Character, Bitmap>();
BitmapRegionDecoder decoder = null;
InputStream is = sContext.getResources()
.openRawResource(R.drawable.big_english);
try {
decoder = BitmapRegionDecoder.newInstance(is, false);
} catch (IOException ex) {
}
int h = decoder.getHeight();
Rect r = new Rect(0, 0, h, h);
for (char c = ABC.first();
c != CharacterIterator.DONE;
c = ABC.next(), r.offset(h, 0)) {
Bitmap bmp = decoder.decodeRegion(r, null);
sImages.put(c, bmp);
}
This works well in Android emulator:
But on a real Moto G device the letters are too big (Maybe by 1.5 factor? When I print sContext.getResources().getDisplayMetrics().density
I for some reason get 2.0):
At the same time the yellow square tile backround is shown correctly.
All (big_tile.png and big_english.png and game_board.png) are PNG-images - so why the difference?
Why does it happen and how to fix this please?
Should I maybe use inDensity
or any other BitmapFactory.Options?
Or is it because of my getResources().openRawResource()
call - but what to use instead?
Upvotes: 2
Views: 1912
Reputation: 23018
I will share my own solution here.
The problem has been, that the yellow background for my letter tiles is a Drawable
and the foreground is a Bitmap
(read with the help of BitmapRegionDecoder
from a PNG-stripe).
For some weird reason I still don't understand - their dimensions differ on some Android devices.
(1) So my easiest workaround has been to scale the Bitmap
(foreground with letter) into the bounds of the Drawable
(yellow square background) every time the letter tile is being drawn:
private Paint mPaint = new Paint(Paint.FILTER_BITMAP_FLAG);
public void draw(Canvas canvas) {
canvas.save();
canvas.translate(left, top);
mImage.draw(canvas);
Bitmap bmp = getImages().get(mLetter);
canvas.drawBitmap(bmp, null, mImage.getBounds(), mPaint);
canvas.restore();
}
(2) My more involved workaround has been to scale the Bitmap
just once - right after I read it with BitmapRegionDecoder
and before I store it in a HashMap:
private static final CharacterIterator ABC =
new StringCharacterIterator("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
private static HashMap<Character, Bitmap> sBitmaps =
new HashMap<Character, Bitmap>();
try {
InputStream is = context.getResources().openRawResource(EN);
BitmapRegionDecoder decoder = BitmapRegionDecoder.newInstance(is, false);
int h = decoder.getHeight();
Rect r = new Rect(0, 0, h, h);
for (char c = ABC.first();
c != CharacterIterator.DONE;
c = ABC.next(), r.offset(h, 0)) {
Bitmap unscaled = decoder.decodeRegion(r, null);
Bitmap scaled = Bitmap.createScaledBitmap(unscaled, (int) (SCALE * width), (int) (SCALE * height), true);
sBitmaps.put(c, scaled);
}
} catch (IOException ex) {
}
(3) Both methods worked, but on the older Google Nexus One device I couldn't see the foregrounds for some reason. At this point I've lost my nerve, stopped using BitmapRegionDecoder
and just split the PNG-stripe with ImageMagick (the command is convert square.png -crop 40x40 square_%d.png
). Now my app uses Drawable
both for foregrounds and backgrounds of letter tiles and works on all devices starting with SDK level 8:
private static final String SQUARE = "square_";
private static final char[] LETTERS = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'};
private static HashMap<Character, Drawable> sLetters =
new HashMap<Character, Drawable>();
for (int i = 0; i < LETTERS.length; i++) {
char c = LETTERS[i];
int id = context.getResources().getIdentifier(PREFIX + i, "drawable", context.getPackageName());
Drawable d = context.getResources().getDrawable(id);
d.setBounds(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight());
sLetters.put(c, d);
}
Upvotes: 0
Reputation: 200
I also have the same problem with image, android devices came with many screen resolution. you will need either put alot of image into your drawable folder or give a set of rule of the image width and height to each screen resolution
for example:
if screen_resolution = 4 inch
int img_height = 200
int img_width = 200
else if screen_resolution = 5 inch
int img_height = 300
int img_width = 300
. . and so on hope this can help you some how.
here some of my code(I use imageview not bitmap sorry):
int width, height;
//calculate device screen
DisplayMetrics metrics=new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
float height=metrics.heightPixels/metrics.xdpi;
float width=metrics.widthPixels/metrics.ydpi;
float inchscreen = FloatMath.sqrt(height*height+width*width);
if (inchscreen > 4.1000)
{
//set image height for device above 4.1 inch screen
height = 400;
width = 400
}
else {
//set image height for device below 4.1 inch screen
height = 280;
width = 280
}
if (imgfile != null) {
int imageResource = getResources().getIdentifier(uri, null,
getPackageName());
Drawable image = getResources().getDrawable(imageResource);
imageview.setImageDrawable(image);
imageview.getLayoutParams().height = h_display;
imageview.getLayoutParams().width = h_display;
}
Upvotes: 2