【问题标题】:Android : Maximum allowed width & height of bitmapAndroid:位图的最大允许宽度和高度
【发布时间】:2013-02-25 04:00:24
【问题描述】:

我正在创建一个需要将大图像解码为位图以显示在 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 的最大值,但我不知道如何获得设备位图的最大允许大小

有什么想法吗?

【问题讨论】:

    标签: android bitmap


    【解决方案1】:

    这个限制应该来自底层的 OpenGL 实现。如果你已经在你的应用中使用了 OpenGL,你可以使用这样的东西来获得最大尺寸:

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

    这表明我的 Galaxy Nexus 和 Galaxy S2 的最大分辨率为 2048x2048。

    不幸的是,如果您还没有使用它,获取 OpenGL 上下文来调用它的唯一方法是创建一个(包括表面视图等),这只是查询最大尺寸的大量开销.

    【讨论】:

    • 感谢您的回复,这也是我的想法。知道这在不同设备上有多大变化吗?
    • 老实说,我不确定。这就是为什么我尝试了两种设备。如果我能找到我的旧 HTC Magic,我也会尝试那个。我知道在标准 OpenGL 上,规范说它总是 >= 1024,但我不确定 OpenGLES。
    • 您可以在不创建 OpenGL 上下文的情况下查询 OpenGL,因为 glGetIntegerv 是一个静态方法:GLES10.glGetIntegerv(GL10.GL_MAX_TEXTURE_SIZE, maxSize, 0);
    • @Geobits 也许你是对的,再次测试我经常得到正确的结果,但有时我得到的只是零。
    • 不幸的是我也得到了零,使用静态方法。
    【解决方案2】:

    获得最大允许大小的另一种方法是循环遍历所有 EGL10 配置并跟踪最大大小。

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

    根据我的测试,这非常可靠,不需要您创建实例。 在性能方面,在我的 Note 2 上执行需要 18 毫秒,而在我的 G3 上只需要 4 毫秒。

    【讨论】:

    • 这似乎对我有用,甚至对于较旧的 API 16 设备,它通常需要
    • 请注意,某些设备有多个最大纹理大小配置。 Kindle Fire HD 7'' (2012) 的配置报告最大纹理大小为 2048 和最大纹理大小为 4096。
    【解决方案3】:

    2048*2048 限制适用于 GN。 GN 是 xhdpi 设备,也许您将图像放在错误的密度桶中。我将一个 720*1280 的图像从 drawable 移动到 drawable-xhdpi 并且它起作用了。

    感谢 Romain Guy 的回答。这是他的答案link

    【讨论】:

      【解决方案4】:

      如果您使用的是 API 级别 14+ (ICS),则可以在 Canvas 类上使用 getMaximumBitmapWidthgetMaximumBitmapHeight 函数。这适用于硬件加速层和软件层。

      我相信 Android 硬件必须至少支持 2048x2048,所以这将是一个安全的最低值。在软件层上,最大尺寸为 32766x32766。

      【讨论】:

      • 我实际上已经尝试过了,它返回的值超过 30k,所以它根本没有帮助
      • 那是因为您的视图没有经过硬件加速。试试canvas.isHardwareAccelerated(),它应该返回true。如果没有,请尝试view.setLayerType(View.LAYER_TYPE_HARDWARE, null) 或在清单中启用硬件加速 (android:hardwareAccelerated="true")。
      • 这个也试过了,还是超过30k
      • getMaximumBitmapWidth()getMaximumBitmapHeight() 方法返回一个静态值 Canvas.MAXMIMUM_BITMAP_SIZE
      【解决方案5】:

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-05-15
        • 2013-09-23
        • 1970-01-01
        • 2012-07-06
        • 2018-09-16
        • 2014-04-04
        • 2014-02-27
        • 2011-08-27
        相关资源
        最近更新 更多