"Растровое изображение слишком большое для загрузки в текстуру"
я загружаю растровое изображение в ImageView и вижу эту ошибку. Я полагаю, что этот предел относится к ограничению размера для аппаратных текстур OpenGL (2048x2048). Изображение, которое мне нужно загрузить, - это изображение с Пинч-зумом высотой около 4000 пикселей.
Я попытался отключить аппаратное ускорение в манифесте, но без радости.
<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 предполагает, что чертежи без классификатора плотности являются 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 (перемещение изображений в
drawable-nodpi
папка) работает, но есть еще одна проблема: Это делает изображения СЛИШКОМ МАЛЕНЬКИЙ на экране, если изображения не изменяются до очень большого (например, 2000 x 3800) разрешения, чтобы соответствовать экрану - тогда это делает ваше приложение тяжелее.решение: поместите файлы изображений в
drawable-hdpi
-- Он работал как шарм для меня.
используя правильный drawable подпапка решила это за меня. Мое решение состояло в том, чтобы поместить мое изображение с полным разрешением (1920x1200) в drawable-xhdpi папка, а не drawable.
Я также поместил уменьшенное изображение (1280x800) в drawable-hdpi.
эти два разрешения соответствуют 2013 и 2012 Nexus 7 таблетки я программирую. Я также протестировал решение на некоторых других таблетки.
@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 вместо прямой загрузки в imageview
скольжение:https://github.com/bumptech/glide
Glide.with(this).load(Uri.parse(filelocation))).into(img_selectPassportPic);