【问题标题】:How I load a 2048x2048 image on Android 2.3?如何在 Android 2.3 上加载 2048x2048 图像?
【发布时间】:2013-05-08 06:10:30
【问题描述】:

这听起来可能很具体……确实如此。

我真的需要在 Android 2.3 上加载 2048x2048 32 位图像(特别是 Nexus One 和 Xperia Play,当前形式的应用程序会因内存不足错误而彻底崩溃)。

Android 2.2 可以正常加载,2.3 之后的所有 android 也可以正常加载,一些 2.3 设备(通常具有巨大的堆)也可以正常加载。

Xperia Play 特别报告(通过 OpenGL)它可以加载高达 4096x4096 的图像,并且使用 Marmalade SDK 我真的可以加载疯狂的巨大图像,其中许多图像很容易使用 150mb 的内存。

但我不知道如何在该设备上使用 Java 加载 2048x2048 图像,它只是抛出了这个错误:

05-07 17:41:25.202:E/GraphicsJNI(27847):VM 不允许我们分配 30965760 字节

编辑:不要再告诉我使用较低的分辨率,我会引用自己的话:

我确实需要在 Android 2.3 上加载 2048x2048 32 位图像

较低的示例图像不是 2048x2048,较高的示例图像也不是 2048x2048,也不是缩放的图像,mipmap 版本或其他任何东西...我需要按原样加载这些图像,期间。

【问题讨论】:

  • 能否降低图像质量(假设是jpg),这样就不会占用太多内存?
  • 它是一个 png,它在未压缩时占用 30mb 的内存。 (压缩后为 500kb)

标签: android


【解决方案1】:

编辑

由于您不想缩小图像,这是可以理解的,您可能需要考虑降低要加载到内存的图像的质量/sizeInMbs。

例如,您说您有一个 2048*2048 的图像,大约需要 30 mb,这对于这样大小的图像来说相当大。

看看这个demo from Romain Guy,他使用的是 1280*752 的图像,但大小只有几百 kb。尽管尺寸很小,但working demo 上的图像看起来非常清晰明快。


首先,将 2048*2048 的图像加载到您提到的那些设备这样的小设备屏幕上是一种资源浪费。这是fully detailed tutorial 的链接,了解如何有效地缩放和加载大图像。

请记住,您应该尽可能缩小图像,Android 开发者网站提到:“具有更高分辨率的图像不会提供任何明显的好处,但仍会占用宝贵的内存并产生额外的性能由于额外的动态缩放而产生的开销。”

第一步,先获取图片尺寸,使用BitmapFactory.Options:

BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(getResources(), R.id.myimage, options);
int imageHeight = options.outHeight;
int imageWidth = options.outWidth;
String imageType = options.outMimeType;

第二步,计算一个采样因子:图片缩小多少

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

最后你可以使用以下方法缩小它:

public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,
    int reqWidth, int reqHeight) {

// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(res, resId, options);

// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);

// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
return BitmapFactory.decodeResource(res, resId, options);
}

【讨论】:

  • 该图像实际上是动画的图像图集,我确实使用了它的整个分辨率,实际上如果我使用正确的设备,最终结果(帧)已经以一半的分辨率显示分辨率,我在 Xperia Play 上需要 4096x4096,在平板电脑上需要 8192x8192...
【解决方案2】:

30965760 字节对于 2048x2048 的分辨率来说听起来相当大。

难道图像是每通道 32 位而不是每通道 8 位?当我要求人们提供 32 位 PNG 时,一个常见的错误是他们在 Photoshop 等程序中选择了 32 位/通道(128 位图像)模式。

红色(8-bit)+绿色(8-bit)+蓝色(8-bit)+Alpha( 8 位) = 32 位 图像。

【讨论】:

    【解决方案3】:

    看看使用 BitmapRegionDecoder 仅加载在任何给定时间可见(或即将可见)的位图部分。见:Using BitmapRegionDecoder to load large images

    【讨论】:

      【解决方案4】:

      您必须缩小位图以减少内存消耗。 建议你看一下Loading Large Bitmaps Efficiently这个问题的官方文档。

      作为一个额外的建议,不要忘记回收所有未使用的位图。这将有助于 GC 更快地释放内存。

      【讨论】:

        【解决方案5】:

        如果您出于某种原因需要全分辨率(与 daniel_c05 的回答中降低的分辨率相反)并且您不能使用 OpenGL(为什么不呢?它非常适合这个),

        1. 将其拆分为图块
        2. 一次只能加载和渲染几个图块
        3. 如果您需要高效缩放,请预先缩放图像(mipmap)并平铺每个级别。

        但实际上,如果您以这种规模工作并想要速度,那么您应该使用 OpenGL。

        【讨论】:

        • OpenGL 可以以某种方式直接从 apk 加载吗?跳过堆?
        • 是和不是。您可以从 apk 加载资产,就像将它们加载到位图中一样。也就是说,您不能使用相同类型的压缩,因此您通常会使用未压缩的资源或使用自己的 png 库。真正的分裂发生是因为 1)这些图像永远不会在未压缩的 Java 领域出现,2)它们可以卸载到 GPU,甚至不需要占用任何 RAM。如果您正在做这样的事情,请使用一个好的 3D 库。我衷心推荐 libgdx。
        • 我不太明白...如何将png文件直接加载到OpenGL中并跳过堆?
        猜你喜欢
        • 2019-08-21
        • 2017-04-21
        • 1970-01-01
        • 1970-01-01
        • 2023-01-29
        • 2014-06-21
        • 1970-01-01
        • 1970-01-01
        • 2014-12-23
        相关资源
        最近更新 更多