157

我正在将位图加载到 ImageView 中,并看到此错误。我收集此限制与 OpenGL 硬件纹理 (2048x2048) 的大小限制有关。我需要加载的图像是大约 4,000 像素高的双指缩放图像。

我试过在清单中关闭硬件加速,但没有任何乐趣。

    <application
        android:hardwareAccelerated="false"
        ....
        >

是否可以将大于 2048 像素的图像加载到 ImageView 中?

4

17 回答 17

409

这不是问题的直接答案(加载图像> 2048),而是任何遇到错误的人的可能解决方案。

就我而言,图像在两个维度上都小于 2048(准确地说是 1280x727),并且在 Galaxy Nexus 上特别遇到了这个问题。图像在drawable文件夹中,没有任何合格的文件夹。Android 假定没有密度限定符的可绘制对象是 mdpi,并针对其他密度将它们放大或缩小,在这种情况下,xhdpi 放大了 2 倍。移动罪魁祸首图像以drawable-nodpi防止缩放解决了该问题。

于 2013-02-14T14:57:56.970 回答
108

我以这种方式缩小了图像:

ImageView iv  = (ImageView)waypointListView.findViewById(R.id.waypoint_picker_photo);
Bitmap d = new BitmapDrawable(ctx.getResources() , w.photo.getAbsolutePath()).getBitmap();
int nh = (int) ( d.getHeight() * (512.0 / d.getWidth()) );
Bitmap scaled = Bitmap.createScaledBitmap(d, 512, nh, true);
iv.setImageBitmap(scaled);
于 2013-03-27T17:57:55.530 回答
51

所有渲染都基于 OpenGL,所以你不能超过这个限制(GL_MAX_TEXTURE_SIZE取决于设备,但最小值是 2048x2048,所以任何低于 2048x2048 的图像都可以)。

有了这么大的图像,如果你想在手机上放大,你应该设置一个类似于你在谷歌地图中看到的系统。将图像分成几部分和几个定义。

或者您可以在显示之前缩小图像(请参阅user1352407对此问题的回答)。

另外,请注意您将图像放入哪个文件夹,Android 可以自动放大图像。看看下面Pilot_51对这个问题的回答。

于 2012-04-22T19:02:27.397 回答
34

与其花费数小时尝试手动编写/调试所有这些下采样代码,不如使用Picasso? 它是为处理bitmaps所有类型和/或大小而设计的。

我已经使用这行代码来消除我的“位图太大......”问题:

Picasso.load(resourceId).fit().centerCrop().into(imageView);
于 2015-03-21T04:23:09.803 回答
21

在 ( ) 中添加以下 2 个属性AndroidManifest.xml对我有用:

android:largeHeap="true"
android:hardwareAccelerated="false"
于 2016-11-27T11:55:14.273 回答
16

drawable-nodpi将图像文件从文件夹更改为文件drawable夹对我有用。

于 2015-12-29T12:59:56.153 回答
9

我用毕加索也遇到了同样的问题。图像至少在尺寸、宽度或高度方面太大。最后我在这里找到了解决方案。您可以根据显示尺寸缩小大图像并保持纵横比:

    public Point getDisplaySize(Display display) {
    Point size = new Point();

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) {
        display.getSize(size);
    } else {
        int width = display.getWidth();
        int height = display.getHeight();
        size = new Point(width, height);
    }

    return size;
}

并使用此方法通过 Picasso 加载图像:

    final Point displySize = getDisplaySize(getWindowManager().getDefaultDisplay());
        final int size = (int) Math.ceil(Math.sqrt(displySize.x * displySize.y));
        Picasso.with(this)
                .load(urlSource)
                .resize(size, size)
                .centerInside()
                .into(imageViewd);

同样为了获得更好的性能,您可以根据显示屏的宽度和高度下载图像,而不是整个图像:

    public String reviseImageUrl(final Integer displayWidth,     final Integer displayHeight,
        final String originalImageUrl) {
    final String revisedImageUrl;

    if (displayWidth == null && displayHeight == null) {
        revisedImageUrl = originalImageUrl;
    } else {
        final Uri.Builder uriBuilder = Uri.parse(originalImageUrl).buildUpon();

        if (displayWidth != null && displayWidth > 0) {
            uriBuilder.appendQueryParameter(QUERY_KEY_DISPLAY_WIDTH, String.valueOf(displayWidth));
        }

        if (displayHeight != null && displayHeight > 0) {
            uriBuilder.appendQueryParameter(QUERY_KEY_DISPLAY_HEIGHT, String.valueOf(displayHeight));
        }

        revisedImageUrl = uriBuilder.toString();
    }

    return revisedImageUrl;
}

    final String newImageUlr = reviseImageUrl(displySize.x, displySize.y, urlSource);

接着:

    Picasso.with(this)
                .load(newImageUlr)
                .resize(size, size)
                .centerInside()
                .into(imageViewd);

编辑:getDisplaySize()

display.getWidth()/getHeight()已弃用。而不是Display使用DisplayMetrics.

public Point getDisplaySize(DisplayMetrics displayMetrics) {
        int width = displayMetrics.widthPixels;
        int height = displayMetrics.heightPixels;
        return new Point(width, height);
}
于 2015-07-30T20:53:32.133 回答
6

BitmapRegionDecoder成功了。

您可以覆盖onDraw(Canvas canvas)、启动新线程并解码用户可见的区域。

于 2013-04-18T21:45:47.417 回答
5

正如 Larcho 所指出的,从 API 级别 10 开始,您可以使用BitmapRegionDecoder从图像中加载特定区域,然后,您可以通过仅在内存中分配所需区域来完成以高分辨率显示大图像。我最近开发了一个库,它通过触摸手势处理提供大图像的可视化。源代码和示例可在此处获得

于 2014-01-05T15:40:36.763 回答
4

查看级别

您可以使用以下代码在运行时为单个视图禁用硬件加速:

myView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);

于 2015-02-05T10:51:43.600 回答
3

我遇到了同样的问题,这是我的解决方案。将图像的宽度设置为与android屏幕宽度相同,然后缩放高度

Bitmap myBitmap = BitmapFactory.decodeFile(image.getAbsolutePath());
Display display = getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);
int width = size.x;
int height = size.y;
Log.e("Screen width ", " "+width);
Log.e("Screen height ", " "+height);
Log.e("img width ", " "+myBitmap.getWidth());
Log.e("img height ", " "+myBitmap.getHeight());
float scaleHt =(float) width/myBitmap.getWidth();
Log.e("Scaled percent ", " "+scaleHt);
Bitmap scaled = Bitmap.createScaledBitmap(myBitmap, width, (int)(myBitmap.getWidth()*scaleHt), true);
myImage.setImageBitmap(scaled);

这对于任何尺寸的安卓屏幕都更好。请让我知道这对你有没有用。

于 2015-05-17T15:28:37.563 回答
2

缩小图像:

BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;

// Set height and width in options, does not return an image and no resource taken
BitmapFactory.decodeStream(imagefile, null, options);

int pow = 0;
while (options.outHeight >> pow > reqHeight || options.outWidth >> pow > reqWidth)
    pow += 1;
options.inSampleSize = 1 << pow; 
options.inJustDecodeBounds = false;
image = BitmapFactory.decodeStream(imagefile, null, options);

图像将按 reqHeight 和 reqWidth 的大小缩小。据我了解, inSampleSize 仅采用 2 个值的幂。

于 2014-02-27T12:39:24.610 回答
2

使用 Glide 库而不是直接加载到 imageview

滑翔:https ://github.com/bumptech/glide

Glide.with(this).load(Uri.parse(filelocation))).into(img_selectPassportPic);
于 2018-05-17T06:56:06.703 回答
1

我一个接一个地尝试了上述所有解决方案,持续了好几个小时,但似乎都没有奏效!最后,我决定四处寻找有关使用 Android 相机捕获图像并显示它们的官方示例。官方的例子(这里),终于给了我唯一有效的方法。下面我介绍我在该示例应用程序中找到的解决方案:

public void setThumbnailImageAndSave(final ImageView imgView, File imgFile) {

            /* There isn't enough memory to open up more than a couple camera photos */
    /* So pre-scale the target bitmap into which the file is decoded */

    /* Get the size of the ImageView */
    int targetW = imgView.getWidth();
    int targetH = imgView.getHeight();

    /* Get the size of the image */
    BitmapFactory.Options bmOptions = new BitmapFactory.Options();
    bmOptions.inJustDecodeBounds = true;
    BitmapFactory.decodeFile(imgFile.getAbsolutePath(), bmOptions);
    int photoW = bmOptions.outWidth;
    int photoH = bmOptions.outHeight;

    /* Figure out which way needs to be reduced less */
    int scaleFactor = 1;
    if ((targetW > 0) || (targetH > 0)) {
        scaleFactor = Math.min(photoW/targetW, photoH/targetH);
    }

    /* Set bitmap options to scale the image decode target */
    bmOptions.inJustDecodeBounds = false;
    bmOptions.inSampleSize = scaleFactor;
    bmOptions.inPurgeable = true;

    /* Decode the JPEG file into a Bitmap */
    Bitmap bitmap = BitmapFactory.decodeFile(imgFile.getAbsolutePath(), bmOptions);

    /* Associate the Bitmap to the ImageView */
    imgView.setImageBitmap(bitmap);
    imgView.setVisibility(View.VISIBLE);
}
于 2015-11-05T11:19:40.867 回答
0

使用正确的可绘制子文件夹为我解决了这个问题。我的解决方案是将全分辨率图像 (1920x1200) 放入drawable-xhdpi文件夹,而不是drawable文件夹。

我还将按比例缩小的图像 (1280x800) 放入drawable-hdpi文件夹。

这两个分辨率与我正在编程的 2013 年和 2012 年 Nexus 7 平板电脑相匹配。我还在其他一些平板电脑上测试了该解决方案。

于 2017-04-21T21:24:51.717 回答
0
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {

    super.onActivityResult(requestCode, resultCode, data);
    ///*
    if (requestCode == PICK_FROM_FILE && resultCode == RESULT_OK && null != data){



        uri = data.getData();

        String[] prjection ={MediaStore.Images.Media.DATA};

        Cursor cursor = getContentResolver().query(uri,prjection,null,null,null);

        cursor.moveToFirst();

        int columnIndex = cursor.getColumnIndex(prjection[0]);

        ImagePath = cursor.getString(columnIndex);

        cursor.close();

        FixBitmap = BitmapFactory.decodeFile(ImagePath);

        ShowSelectedImage = (ImageView)findViewById(R.id.imageView);

      //  FixBitmap = new BitmapDrawable(ImagePath);
        int nh = (int) ( FixBitmap.getHeight() * (512.0 / FixBitmap.getWidth()) );
        FixBitmap = Bitmap.createScaledBitmap(FixBitmap, 512, nh, true);

       // ShowSelectedImage.setImageBitmap(BitmapFactory.decodeFile(ImagePath));

        ShowSelectedImage.setImageBitmap(FixBitmap);

    }
}

这段代码是工作

于 2017-07-16T07:19:33.087 回答
0

对于那些想要放置小尺寸图像的人的注意事项:

Pilot_51的解决方案(将图像移动到drawable-nodpi文件夹)有效,但还有另一个问题:它会使图像在屏幕上变得太小,除非图像被调整到非常大(如 2000 x 3800)的分辨率以适合屏幕 - 然后它会使您的应用程序更重.

解决方案:把你的图像文件放进去drawable-hdpi——它对我来说就像一个魅力。

于 2016-06-30T18:07:12.753 回答