"Растровое изображение слишком велико для загрузки в текстуру"
Я загружаю растровое изображение в ImageView и вижу эту ошибку. Я полагаю, что это ограничение относится к ограничению размера для аппаратных текстур OpenGL (2048x2048). Изображение, которое мне нужно загрузить, представляет собой изображение с пинч-зумом высотой около 4000 пикселей.
Я пытался отключить аппаратное ускорение в манифесте, но без радости.
<application
android:hardwareAccelerated="false"
....
>
Можно ли загрузить изображение размером более 2048 пикселей в ImageView?
18 ответов
Все рендеринг основан на OpenGL, так что вы не можете превысить этот предел (GL_MAX_TEXTURE_SIZE
зависит от устройства, но минимум составляет 2048x2048, поэтому подойдет любое изображение размером ниже 2048x2048).
С такими большими изображениями, если вы хотите уменьшить масштаб и на мобильном устройстве, вы должны настроить систему, подобную той, что вы видите на картах Google, например. Изображение разделено на несколько частей и несколько определений.
Или вы можете уменьшить изображение перед его отображением (см . Ответ пользователя 1353540 на этот вопрос).
А также, будьте осторожны, в какую папку вы помещаете изображение, Android может автоматически увеличивать изображения. Посмотрите ответ Pilot_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);
Вместо того, чтобы часами часами пытаться написать / отладить весь этот код сокращения вручную, почему бы не использовать Picasso
? Это было сделано для борьбы с bitmaps
всех типов и / или размеров.
Я использовал эту единственную строку кода, чтобы удалить мою проблему "слишком большое растровое изображение…":
Picasso.load(resourceId).fit().centerCrop().into(imageView);
Добавление следующих 2 атрибутов в (AndroidManifest.xml
) у меня сработало
android:largeHeap="true"
android:hardwareAccelerated="false"
Изменение файла изображения на drawable-nodpi
папка из drawable
папка работала у меня.
Я использовал Пикассо и у меня была такая же проблема. изображение было слишком большим, по крайней мере, по размеру, ширине или высоте. наконец я нашел решение здесь. Вы можете уменьшить масштаб изображения в соответствии с размером экрана, а также сохранить соотношение сторон:
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()
устарела. Вместо Display
использование DisplayMetrics
,
public Point getDisplaySize(DisplayMetrics displayMetrics) {
int width = displayMetrics.widthPixels;
int height = displayMetrics.heightPixels;
return new Point(width, height);
}
BitmapRegionDecoder
делает трюк.
Вы можете переопределить onDraw(Canvas canvas)
, запустите новую тему и расшифруйте область, видимую пользователю.
Как отметил Ларчо, начиная с уровня API 10, вы можете использовать BitmapRegionDecoder
чтобы загрузить определенные области из изображения, и с этим вы можете показать большое изображение в высоком разрешении, выделяя в памяти только необходимые области. Недавно я разработал библиотеку, которая обеспечивает визуализацию больших изображений с помощью сенсорных жестов. Исходный код и примеры доступны здесь.
Посмотреть уровень
Вы можете отключить аппаратное ускорение для отдельного представления во время выполнения с помощью следующего кода:
myView.setLayerType (View.LAYER_TYPE_SOFTWARE, null);
Я столкнулся с той же проблемой, вот мое решение. установить ширину изображения так же, как ширина экрана 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. дайте мне знать, если это работает для вас.
Используйте библиотеку Glide вместо прямой загрузки в imageview
Glide: https://github.com/bumptech/glide
Glide.with(this).load(Uri.parse(filelocation))).into(img_selectPassportPic);
Уменьшить изображение:
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 значения.
Я пробовал все вышеописанные решения, одно за другим, довольно много часов, и ни одно из них не помогло! Наконец, я решил поискать официальный пример, касающийся захвата изображений с помощью камеры 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);
}
Добавьте этот код в манифест
<activity
android:name="com.yalantis.ucrop.UCropActivity"
android:screenOrientation="portrait"
android:hardwareAccelerated="false"
android:theme="@style/Theme.AppCompat.Light.NoActionBar" />
Примечание для тех, кто хочет поставить изображения малого размера:
Решение Pilot_51 (перемещение ваших изображений в drawable-nodpi
папка) работает, но имеет еще одну проблему: она делает изображения СЛИШКОМ МАЛЕНЬКИМИ на экране, если только изображения не были изменены до очень большого (например, 2000 x 3800) разрешения, чтобы соответствовать экрану - тогда это делает ваше приложение более тяжелым.
РЕШЕНИЕ: поместите ваши файлы изображений в drawable-hdpi
- Это сработало как обаяние для меня.
@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);
}
}
Этот код работает
Использование правильной прорисовываемой подпапки решило это для меня. Мое решение состояло в том, чтобы поместить мое изображение в полном разрешении (1920x1200) в папку drawable-xhdpi вместо папки drawable.
Я также поместил уменьшенное изображение (1280x800) в папку drawable-hdpi.
Эти два разрешения соответствуют планшетам Nexus 7 2013 и 2012 года, которые я программирую. Я также проверил решение на некоторых других планшетах.