"Растровое изображение слишком велико, чтобы быть загруженным в текстуру"
Я загружаю растровое изображение в ImageView и вижу эту ошибку. Я понимаю, что это ограничение относится к пределу размера для аппаратных текстур OpenGL (2048x2048). Изображение, которое мне нужно загрузить, - это изображение с максимальным увеличением около 4000 пикселей.
Я попытался отключить аппаратное ускорение в манифесте, но не радость.
<application
android:hardwareAccelerated="false"
....
>
Возможно ли загрузить изображение размером более 2048 пикселей в ImageView?
Ответы
Ответ 1
Все рендеринг основан на OpenGL, поэтому вы не можете преодолеть этот предел (GL_MAX_TEXTURE_SIZE
зависит от устройства, но минимум 2048x2048, поэтому любое изображение ниже 2048x2048 будет соответствовать).
С такими большими изображениями, если вы хотите увеличить масштаб и на мобильном устройстве, вы должны настроить систему, аналогичную той, что вы видите на картах Google, например. С изображением, разделенным на несколько частей, и несколькими определениями.
Или вы можете масштабировать изображение перед его отображением (см. user1352407 ответ по этому вопросу).
Кроме того, будьте осторожны, в какую папку вы помещаете изображение, Android может автоматически масштабировать изображения. Посмотрите Pilot_51 ответ ниже по этому вопросу.
Ответ 2
Это не прямой ответ на вопрос (загрузка изображений > 2048), но возможное решение для любого, кто испытывает ошибку.
В моем случае изображение было меньше, чем 2048 в обоих измерениях (точнее, 1280x727), и проблема была конкретно связана с Galaxy Nexus. Изображение находилось в папке drawable
и ни одной из квалифицированных папок. Android предполагает выделение без спецификатора плотности mdpi и масштабирует их вверх или вниз для других плотностей, в этом случае масштабируется 2x для xhdpi. Перемещение изображения преступника в drawable-nodpi
, чтобы предотвратить масштабирование, решило проблему.
Ответ 3
Я уменьшил изображение таким образом:
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);
Ответ 4
Вместо того, чтобы тратить часы на часы, пытаясь написать/отладить весь этот код понижающей выборки вручную, почему бы не использовать Picasso? Он был создан для обработки растровых изображений всех типов и/или размеров.
Я использовал эту единственную строку кода для удаления моей "растровой слишком большой..." проблемы:
Picasso.with(context).load(resourceId).fit().centerCrop().into(imageView);
Ответ 5
Мне удалось изменить файл изображения в папку drawable-nodpi
из папки drawable
.
Ответ 6
Я использовал Пикассо и имел ту же проблему. изображение было слишком большим, по крайней мере, по размеру, ширине или высоте. наконец, я нашел решение здесь. вы можете масштабировать большое изображение вниз в соответствии с размером дисплея, а также сохранить соотношение сторон:
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);
EDIT: 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
BitmapRegionDecoder делает трюк.
Вы можете переопределить onDraw (Canvas canvas), запустить новый поток и декодировать, видны пользователю.
Ответ 8
Как указано Larcho, начиная с уровня API 10, вы можете использовать BitmapRegionDecoder
для загрузки определенных областей из изображения, и с этим вы можете сделать, чтобы показать большое изображение с высоким разрешением, выделив в памяти только нужные регионы, Недавно я разработал библиотеку, которая обеспечивает визуализацию больших изображений при помощи сенсорного жеста. Исходный код и образцы доступны здесь.
Ответ 9
Для меня работали следующие два атрибута в (AndroidManifest.xml):
- Android: largeHeap = "истинный"
- Android: hardwareAccelerated = "ложь"
Ответ 10
Я столкнулся с той же проблемой, вот мое решение. установите ширину изображения так же, как и ширину экрана андроида, а затем масштабируйте высоту
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. сообщите мне, если это сработает для вас.
Ответ 11
Уменьшить изображение:
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 значения.
Ответ 12
Спасибо всем участникам здесь, но я пробовал все решения выше, один за другим, в течение довольно многих часов, и никто не работает! Наконец, я решил осмотреть официальный пример, касающийся захвата изображений с помощью камеры 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);
}
Хотел бы я знать это раньше... все эти часы: D
Ответ 13
Уровень просмотра
Вы можете отключить аппаратное ускорение для отдельного представления во время выполнения с помощью следующего кода:
myView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
Ответ 14
ЗАМЕЧАНИЕ ДЛЯ ТЕХ, КОТОРЫЕ ХОТЯТ ИЗМЕНИТЬ ИЗОБРАЖЕНИЯ МАЛОГО РАЗМЕРА:
Решение Pilot_51 (перемещение ваших изображений в папку drawable-nodpi
) работает, но имеет другую проблему:
Он отображает изображения СЛИШКОМ МАЛЫХ на экране, если изображение не будет изменено до очень большого (например, 2000 x 3800) разрешение, чтобы оно соответствовало экрану - тогда оно делает ваше приложение более тяжелым.
РЕШЕНИЕ: поместите ваши файлы изображений в drawable-hdpi
- для меня это работало как прелесть.
Ответ 15
Используя правильную подпапку drawable, она решила это для меня. Мое решение состояло в том, чтобы поместить изображение с полным разрешением (1920x1200) в папку drawable-xhdpi вместо папки drawable.
Я также поместил уменьшенное изображение (1280x800) в папку drawable-hdpi.
Эти две резолюции соответствуют планам Nexus 7 2013 и 2012, которые я программирую. Я также тестировал решение на некоторых других планшетах.
Ответ 16
@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);
}
}
Этот код работает
Ответ 17
Я использую webview для слишком большого разрешения.
1-) Создайте отзывчивый html файл, как показано ниже.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<style>
html, body, img {
margin: 0;
padding: 0;
height: 100%;
display: block;
}
</style>
</head>
<body>
<img src="img/program_first.png">
</body>
</html>
2-) Я использую изображение 5708x1634 в папке "img", которая очень большая по горизонтали.
3-) Добавьте "webview" ваш макет и установите нагрузку следующим образом. "program1" - это имя переменной WebView.
program1.loadUrl("file:///android_asset/program/content.html");