"Растровое изображение слишком большое для загрузки в текстуру"
я загружаю растровое изображение в ImageView и вижу эту ошибку. Я полагаю, что это ограничение относится к ограничению размера для аппаратных текстур OpenGL (2048x2048). Изображение, которое мне нужно загрузить, - это изображение с Пинч-зумом высотой около 4,000 пикселей.
Я попытался отключить аппаратное ускорение в манифесте, но без радости.
<application
android:hardwareAccelerated="false"
....
>
можно ли загрузить изображение размером более 2048 пикселей в ImageView?
17 ответов
весь рендеринг основан на OpenGL, поэтому нет, вы не можете перейти этот предел (GL_MAX_TEXTURE_SIZE
зависит от устройства,но минимум 2048x2048, поэтому любое изображение ниже 2048x2048 подойдет).
С такими большими изображениями, если вы хотите увеличить масштаб, и в мобильном телефоне, вы должны настроить систему, похожую на то, что вы видите в Google maps, например. С изображением, разделенным на несколько частей, и несколькими определениями.
или вы можете уменьшить масштаб изображения перед его отображением (см. user1352407 это по этому вопросу).
а также, будьте осторожны, в какую папку вы помещаете изображение, Android может автоматически масштабировать изображения. Взгляните на Pilot_51 это ниже по этому вопросу.
это не прямой ответ на вопрос (загрузка картинки >2048), но возможное решение для тех, кто испытывает ошибку.
в моем случае изображение было меньше 2048 в обоих измерениях (1280x727, если быть точным), и проблема была специально испытана на Galaxy Nexus. Изображение было в drawable
папка и ни одна из квалифицированных папок. Android предполагает, что drawables без классификатора плотности являются mdpi и масштабирует их вверх или вниз для других плотностей, в этом случае масштабирование 2x для xhdpi. Перемещение изображения виновника в 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);
вместо того, чтобы тратить часы на часы, пытаясь написать / отладить весь этот код downsampling вручную, почему бы не использовать Picasso
? Он был создан для того, чтобы иметь дело с bitmaps
всех типов и/или размеров.
я использовал эту единственную строку кода, чтобы удалить мой "растровое изображение слишком большое....":
Picasso.with(context).load(resourceId).fit().centerCrop().into(imageView);
Я использовал Пикассо и имел ту же проблему. изображение было слишком большим, по крайней мере, по размеру, ширине или высоте. наконец-то я нашел решение. вы можете масштабировать большое изображение в соответствии с размером дисплея, а также сохранить соотношение сторон:
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);
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);
}
добавление следующих 2 атрибутов в (AndroidManifest.xml
) работал для меня:
android:largeHeap="true"
android:hardwareAccelerated="false"
BitmapRegionDecoder
делает трюк.
можно переопределить onDraw(Canvas canvas)
, запустите Новый Поток и декодируйте область, видимую пользователю.
как указал Ларчо, начиная с уровня API 10, вы можете использовать BitmapRegionDecoder
чтобы загрузить определенные области из изображения, и с этим, вы можете выполнить, чтобы показать большое изображение в высоком разрешении, выделив в памяти только необходимые области. Недавно я разработал lib, который обеспечивает визуализацию больших изображений с помощью сенсорной обработки жестов. исходный код и образцы доступны здесь.
я столкнулся с той же проблемой, вот мое решение. установите ширину изображения такой же, как ширина экрана 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. дай мне знать, если это сработает.
уменьшить масштаб изображения:
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 значения.
просмотр
вы можете отключить аппаратное ускорение для отдельного вида выполнения со следующим кодом:
Как myview.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
Я пробовал все решения выше, один за другим, в течение многих часов, и ни один из них не работал! Наконец, я решил поискать официальный пример, касающийся захвата изображений с помощью камеры 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);
}
ПРИМЕЧАНИЕ ДЛЯ ТЕХ, КТО ХОЧЕТ ПОМЕСТИТЬ ИЗОБРАЖЕНИЯ НЕБОЛЬШОГО РАЗМЕРА:
решение Pilot_51 (перемещение изображений в ) работает, но имеет другую проблему: Он делает изображения СЛИШКОМ МАЛО на экране, если изображения не изменяются до очень большого (например, 2000 x 3800) разрешения, чтобы соответствовать экрану - тогда это делает ваше приложение тяжелее.
решение: поместите файлы изображений в drawable-hdpi
-- Он работал как шарм для меня.
используя правильный drawable вложенная папка решила это для меня. Мое решение было поставить мое полное разрешение (1920х1200) в drawable-xhdpi, вместо drawable.
Я также поместил уменьшенное изображение (1280x800) в drawable-hdpi.
эти два разрешения соответствуют планшетам Nexus 7 2013 и 2012, которые я программирую. Я также протестировал решение на некоторых других таблетки.
@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);
}
}
этот код-work
используйте библиотеку Glide вместо прямой загрузки в imageview
скольжение:https://github.com/bumptech/glide
Glide.with(this).load(Uri.parse(filelocation))).into(img_selectPassportPic);