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

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

我试过关掉载货单上的硬件加速但没用。

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

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

113925 次浏览

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

有了这样的大图像,如果你想放大,并在移动,你应该设置一个系统类似于你看到的谷歌地图,例如。随着图像分成几个部分,和几个定义。

或者您可以在显示图像之前缩放它(请参阅关于此问题的 User1352407的答案)。

而且,小心你把图片放到哪个文件夹,Android 可以自动放大图片。看看下面关于这个问题的 W 行 T _ 51的回答

这不是对这个问题的直接回答(载入图像 > 2048) ,但是对于任何经历这个错误的人来说,这是一个可能的解决方案。

就我而言,这张照片在两个维度上都小于2048(确切地说是1280x727) ,而且这个问题是在 Galaxy Nexus 上特别体验到的。该图像位于 drawable文件夹中,没有任何限定文件夹。Android 假设没有密度限定符的可绘制内容为 mdpi,并对其他密度进行向上或向下调整,在本例中,对于 xhdpi 调整为2倍。将罪魁祸首图像移动到 drawable-nodpi以防止缩放解决了这个问题。

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

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

BitmapRegionDecoder就行了。

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

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

缩小图片:

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

视野开阔

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

SetLayerType (View.LAYER _ TYPE _ SOFTWARE,null) ;

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

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

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

我遇到了同样的问题,这是我的解决方案。将图像的宽度设置为与 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);

这是更好的任何大小的安卓屏幕。让我知道它是否适合你。

我用了毕加索,也有同样的问题。图像太大,至少在大小,宽度或高度。我终于在这里找到了解决办法。你可以根据显示器的大小缩放大图,也可以保持高宽比:

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

并使用这种方法载入毕加索的图像:

    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()。请使用 DisplayMetrics代替 Display

public Point getDisplaySize(DisplayMetrics displayMetrics) {
int width = displayMetrics.widthPixels;
int height = displayMetrics.heightPixels;
return new Point(width, height);
}

我试了上面所有的方法,一个接一个,试了好几个小时,似乎没有一个奏效!最后,我决定寻找一个官方的例子,关于用 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);
}

将图像文件从 drawable文件夹改为 drawable-nodpi文件夹对我来说很有效。

对于那些想要放置小尺寸图片的人,请注意:

Pilot _ 51的解决方案(将图像移动到 drawable-nodpi文件夹)是可行的,但是还有另一个问题: 它使图像在屏幕上 太小了,除非图像被调整到一个非常大的分辨率(如2000 x 3800) ,以适应屏幕-然后它使你的应用程序更重。

解决方案 : 把你的图像文件放在 drawable-hdpi中——这对我来说非常有效。

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

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

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

我还将一个缩小的图像(1280x800)放入 可绘制的-hdpi文件夹。

这两个分辨率与我正在编程的2013年和2012年的 Nexus7平板电脑相匹配。我还在其他一些药片上测试了这种溶液。

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


}
}

这个代码是工作

使用 Glide 库,而不是直接加载到图像视图中

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

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