【问题标题】:Images loaded with BitmapRegionDecoder are ok on simulator, but too large on device使用 BitmapRegionDecoder 加载的图像在模拟器上正常,但在设备上太大
【发布时间】:2014-11-12 17:42:57
【问题描述】:

a simple word game app 中,我使用以下代码从PNG-image stripe 加载26 个字母的平铺图像:

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);
}       

这在 Android 模拟器中运行良好:

但在真正的 Moto G 设备上,字母太大(可能是 1.5 倍?当我打印 sContext.getResources().getDisplayMetrics().density 时,出于某种原因,我得到了 2.0):

同时the yellow square tile backround显示正确。

所有(big_tile.pngbig_english.pnggame_board.png)都是 PNG 图像 - 那为什么会有区别?

为什么会发生这种情况以及如何解决这个问题?

我是否应该使用inDensity 或任何其他BitmapFactory.Options

或者是因为我的getResources().openRawResource() 调用 - 但改用什么?

【问题讨论】:

  • 不同的屏幕分辨率?
  • 是的,但是黄色方形瓷砖背景显示正确。两者(big_tile.pngbig_english.png)都是 PNG 图像 - 那么为什么会有区别呢?
  • 将 R.drawable.big_english 放到 drawable-nodpi 文件夹中
  • 但我不想在较小的 Android 设备上浪费内存。 res/drawable-xxhdpi/big_english.png 是 6240 x 240 像素。我想在低端设备上使用更小的res/drawable-ldpi/big_english.png
  • 你是把所有的图片都放在只Drawable文件夹里还是放在所有mdpi、hdpi、xhdpi、xxhdpi文件夹里?

标签: android bitmap bitmapfactory android-bitmap bitmapregiondecoder


【解决方案1】:

我也有同样的图像问题,安卓设备有很多屏幕分辨率。您需要将大量图像放入可绘制文件夹中,或者为每个屏幕分辨率提供一组图像宽度和高度规则

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

。 . 等等 希望这对您有所帮助。

这里是我的一些代码(对不起,我使用的是图像视图而不是位图):

int 宽度,高度;

   //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;
                    }

【讨论】:

    【解决方案2】:

    我将在这里分享我自己的解决方案。

    问题是,我的字母图块的黄色背景是Drawable,前景是Bitmap(在BitmapRegionDecoder 的帮助下从PNG 条纹中读取)。

    由于某些奇怪的原因,我仍然不明白 - 它们的尺寸在某些 Android 设备上有所不同。

    (1) 所以my easiest workaround 已经将Bitmap(带有字母的前景)缩放到Drawable(黄色方形背景)的范围内绘制:

    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) 我的more involved workaround 只对Bitmap 进行了一次缩放——就在我用BitmapRegionDecoder 读取它之后并将它存储在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) 两种方法都有效,但在较旧的 Google Nexus One 设备上,由于某种原因我看不到前景。在这一点上,我已经失去了勇气,停止使用BitmapRegionDecoder 并使用 ImageMagick 分割 PNG 条纹(命令是 convert square.png -crop 40x40 square_%d.png)。现在my appDrawable 用于字母图块的前景和背景,并且适用于从 SDK 级别 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);
    } 
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-05-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-12-23
      • 2015-06-11
      • 2013-07-08
      相关资源
      最近更新 更多