“位图太大而无法上传到纹理中”

时间:2012-04-22 18:53:33

标签: android android-imageview android-image android-bitmap

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

我已尝试关闭清单中的硬件加速,但没有快乐。

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

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

17 个答案:

答案 0 :(得分:387)

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

在我的情况下,图像在两个维度上都小于2048(准确地说是1280x727),并且问题是在Galaxy Nexus上经历的。该图像位于drawable文件夹中,没有任何限定文件夹。 Android假定没有密度限定符的drawable是mdpi,并将其缩放或缩小以获得其他密度,在这种情况下,xhdpi的扩展为2x。将罪魁祸首图像移动到drawable-nodpi以防止缩放解决了问题。

答案 1 :(得分:101)

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

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

答案 2 :(得分:45)

所有渲染都基于OpenGL,因此不能超过此限制(GL_MAX_TEXTURE_SIZE取决于设备,但最小值为2048x2048,因此任何低于2048x2048的图像都适合)。

如果您要放大这些大图像,并且在移动设备中,您应该设置类似于您在Google地图中看到的系统。图像分为几个部分,并有几个定义。

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

另外,请注意将图像放入哪个文件夹,Android可以自动放大图像。在这个问题上查看下面的Pilot_51's answer

答案 3 :(得分:34)

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

我使用这一行代码删除了我的&#34;位图太大了....&#34; 问题:

Picasso.load(resourceId).fit().centerCrop().into(imageView);

答案 4 :(得分:16)

将图像文件从drawable-nodpi文件夹中的drawable文件夹更改为我工作。

答案 5 :(得分:10)

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

android:largeHeap="true"
android:hardwareAccelerated="false"

答案 6 :(得分: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);
}

答案 7 :(得分:6)

BitmapRegionDecoder可以解决问题。

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

答案 8 :(得分:5)

正如Larcho所指出的,从API级别10开始,您可以使用BitmapRegionDecoder从图像中加载特定区域,通过这种方式,您可以通过在内存中分配仅显示高分辨率的大图像需要的地区。我最近开发了一个lib,它通过触摸手势处理提供大图像的可视化。 The source code and samples are available here

答案 9 :(得分: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);

这适用于任何尺寸的Android屏幕。让我知道它是否适合你。

答案 10 :(得分:2)

查看级别

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

myView.setLayerType(View.LAYER_TYPE_SOFTWARE,null);

答案 11 :(得分:1)

我已经尝试了上面所有的解决方案,一个接一个,很长时间,但似乎都没有工作!最后,我决定四处寻找有关使用Android相机捕捉图像并显示它们的官方示例。官方的例子(here)终于给了我唯一有效的方法。下面我将介绍我在该示例应用程序中找到的解决方案:

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

答案 12 :(得分:1)

缩小图片:

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个值的幂。

答案 13 :(得分:0)

注意那些想要小尺寸图像的人:

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

解决方案:将您的图片文件放入drawable-hdpi - 这对我来说就像是一种魅力。

答案 14 :(得分:0)

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

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

这两项决议与2013年和2012年Nexus 7平板电脑的编程相匹配。我还在其他平板电脑上测试了该解决方案。

答案 15 :(得分: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);

    }
}

此代码正常工作

答案 16 :(得分:0)

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

Glide:https://github.com/bumptech/glide

Glide.with(this).load(Uri.parse(filelocation))).into(img_selectPassportPic);