29

我正在创建一个需要将大图像解码为位图以显示在 ImageView 中的应用程序。

如果我只是尝试将它们直接解码为位图,我会收到以下错误“位图太大而无法上传到纹理中(1944x2592,max=2048x2048)”

因此,为了能够显示分辨率太高的图像,我使用:

Bitmap bitmap = BitmapFactory.decodeFile(path);

if(bitmap.getHeight()>=2048||bitmap.getWidth()>=2048){
    DisplayMetrics metrics = new DisplayMetrics();
    getWindowManager().getDefaultDisplay().getMetrics(metrics);
    int width = metrics.widthPixels;
    int height = metrics.heightPixels;
    bitmap =Bitmap.createScaledBitmap(bitmap, width, height, true);             
}

这可行,但我真的不想像现在在 if 语句中那样硬编码 2048 的最大值,但我不知道如何获得设备位图的最大允许大小

有任何想法吗?

4

5 回答 5

13

Another way of getting the maximum allowed size would be to loop through all EGL10 configurations and keep track of the largest size.

public static int getMaxTextureSize() {
    // Safe minimum default size
    final int IMAGE_MAX_BITMAP_DIMENSION = 2048;

    // Get EGL Display
    EGL10 egl = (EGL10) EGLContext.getEGL();
    EGLDisplay display = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);

    // Initialise
    int[] version = new int[2];
    egl.eglInitialize(display, version);

    // Query total number of configurations
    int[] totalConfigurations = new int[1];
    egl.eglGetConfigs(display, null, 0, totalConfigurations);

    // Query actual list configurations
    EGLConfig[] configurationsList = new EGLConfig[totalConfigurations[0]];
    egl.eglGetConfigs(display, configurationsList, totalConfigurations[0], totalConfigurations);

    int[] textureSize = new int[1];
    int maximumTextureSize = 0;

    // Iterate through all the configurations to located the maximum texture size
    for (int i = 0; i < totalConfigurations[0]; i++) {
        // Only need to check for width since opengl textures are always squared
        egl.eglGetConfigAttrib(display, configurationsList[i], EGL10.EGL_MAX_PBUFFER_WIDTH, textureSize);

        // Keep track of the maximum texture size
        if (maximumTextureSize < textureSize[0])
            maximumTextureSize = textureSize[0];
    }

    // Release
    egl.eglTerminate(display);

    // Return largest texture size found, or default
    return Math.max(maximumTextureSize, IMAGE_MAX_BITMAP_DIMENSION);
}

From my testing, this is pretty reliable and doesn't require you to create an instance. Performance-wise, this took 18 milliseconds to execute on my Note 2 and only 4 milliseconds on my G3.

于 2014-11-08T23:24:45.977 回答
10

This limit should be coming from the underlying OpenGL implementation. If you're already using OpenGL in your app, you can use something like this to get the maximum size:

int[] maxSize = new int[1];
gl.glGetIntegerv(GL10.GL_MAX_TEXTURE_SIZE, maxSize, 0);
// maxSize[0] now contains max size(in both dimensions)

This shows that my both my Galaxy Nexus and Galaxy S2 have a maximum of 2048x2048.

Unfortunately, if you're not already using it, the only way to get an OpenGL context to call this from is to create one(including the surfaceview, etc), which is a lot of overhead just to query a maximum size.

于 2013-03-09T19:18:44.313 回答
2

这将在加载到内存之前解码和缩放图像,只需将横向和纵向更改为您实际想要的大小

BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(path, options);
int imageHeight = options.outHeight;
int imageWidth = options.outWidth;
String imageType = options.outMimeType;
if(imageWidth > imageHeight) {
    options.inSampleSize = calculateInSampleSize(options,512,256);//if landscape
} else{
    options.inSampleSize = calculateInSampleSize(options,256,512);//if portrait
}
options.inJustDecodeBounds = false;
bitmap = BitmapFactory.decodeFile(path,options);

尺寸计算方法

public static int calculateInSampleSize(
        BitmapFactory.Options options, int reqWidth, int reqHeight) {
   // Raw height and width of image
   final int height = options.outHeight;
   final int width = options.outWidth;
   int inSampleSize = 1;

   if (height > reqHeight || width > reqWidth) {

      // Calculate ratios of height and width to requested height and width
      final int heightRatio = Math.round((float) height / (float) reqHeight);
      final int widthRatio = Math.round((float) width / (float) reqWidth);

      // Choose the smallest ratio as inSampleSize value, this will guarantee
      // a final image with both dimensions larger than or equal to the
      // requested height and width.
      inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
   }

   return inSampleSize;
}
于 2013-03-09T17:56:41.987 回答
2

If you're on API level 14+ (ICS) you can use the getMaximumBitmapWidth and getMaximumBitmapHeight functions on the Canvas class. This would work on both hardware accelerated and software layers.

I believe the Android hardware must at least support 2048x2048, so that would be a safe lowest value. On software layers, the max size is 32766x32766.

于 2013-03-09T22:06:22.323 回答
1

The 2048*2048 limit is for GN. GN is a xhdpi device and perhaps you put the image in the wrong density bucket. I moved a 720*1280 image from drawable to drawable-xhdpi and it worked.

Thanks for the answer by Romain Guy. Here's the link of his answer.

于 2013-12-27T01:42:39.883 回答