"Растрові зображення занадто великі для завантаження в текстуру"


154

Я завантажую растровий файл у ImageView і бачу цю помилку. Я вважаю, що це обмеження стосується обмеження розміру для апаратних текстур OpenGL (2048x2048). Зображення, яке мені потрібно завантажити, - це зображення із збільшенням 4000 пікселів.

Я намагався вимкнути апаратне прискорення в маніфесті, але ніякої радості.

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

Чи можна завантажити зображення розміром більше 2048 пікселів у ImageView?


1
Для тих, хто шукає тут, не забудьте поставити своє зображення у подання прокрутки, якщо ви хочете, щоб воно могло прокручуватися. Це дозволить позбутися від помилки. Я витратив деякий час, перш ніж зрозумів, що це моя проблема.
Джейсон Райдж

Для всіх, хто хоче відображати великі зображення, які зберігають якість зображення, зверніться до бібліотеки у відповіді @stoefln нижче. Я використав це і варто спробувати. Однозначно краще, ніж inSampleSizeпідхід.
Махендра Лія

1
@Joe Blow поточна відповідь не працювала у вашому випадку? Якщо ні, то, будь ласка, розкажіть про проблему, з якою ви стикалися в контексті цього питання?
Pravin Divraniya

1
Ей @ VC.One - дивно, що треба працювати над моєю людиною. Я повинен був натиснути "Нагородити наявну відповідь". Ніхто не турбує нудно натискаючи кнопку "найкращого" на цьому спливаючому вікні, тому що це нерозумно :) Це все вирішено, коли я натиснув щедроту. Ура !!
Fattie

1
Я намагаюся завжди виплачувати щедрості (мені не подобається збирати бали). Я думаю, якщо ти натиснеш на мій профіль, тоді щедро, @ VC.One ви побачите багато справді чудових QA від SO !!!
Fattie

Відповіді:


48

Вся візуалізація базується на OpenGL, тому ні в якому разі не можна перевищувати цю межу (GL_MAX_TEXTURE_SIZE залежить від пристрою, але мінімум - 2048x2048, тому будь-яке зображення нижче 2048x2048 підійде).

З такими великими зображеннями, якщо ви хочете збільшити масштаб, а також на мобільному пристрої, вам слід налаштувати систему, аналогічну тій, яку ви бачите, наприклад, на картах Google. Із зображенням розділено на кілька частин і кілька визначень.

Або ви можете зменшити масштаб зображення перед його відображенням (див . Відповідь користувача1352407 на це запитання1352407).

А також будьте обережні, у яку папку ви вкладете зображення, Android може автоматично масштабувати зображення. Подивіться нижче на це запитання відповідь Pilot_51 .


23
Якщо це так, як програма Галерея дозволяє відображати та маніпулювати зображеннями, зробленими фотоапаратом? 2048x2048 - це лише 4-мегапіксельне зображення, і багато Android-телефонів роблять фотографії набагато більшими, ніж це, і програма Галерея, схоже, не має проблем.
Оллі C

3
Оскільки GL_MAX_TEXTURE_SIZE залежить від пристрою.
jptsetung

24
Це справді не має сенсу. Зараз я зіткнувся з тією ж проблемою - із зображенням 1286x835 пікселів. І: тільки на Galaxy Nexus я отримую це повідомлення про помилку і жодне зображення! Це просто здається смішним, що передовий смартфон не може відображати таке маленьке зображення! Мій HTC Hero здатний це показати! Що я можу зробити?
Зордід

1
Дивіться відповідь Ромена тут: stackoverflow.com/questions/7428996/…
Бен Лі

3
@OlilieC Я також хотів би знати, як це роблять програми галереї. Тож якщо хтось знає чи має приклад для показу великих зображень, це було б чудово.
Іннова

408

Це не пряма відповідь на питання (завантаження зображень> 2048), але можливе рішення для тих, хто відчуває помилку.

У моєму випадку зображення було меншим за 2048 в обох вимірах (точніше 1280x727), і проблема була спеціально випробувана на Galaxy Nexus. Зображення було в drawableпапці, і жодна з кваліфікованих папок. Android передбачає, що малюнки без класифікатора щільності є mdpi і масштабують їх вгору або вниз для інших густин, в цьому випадку збільшують в 2 рази на xhdpi. Переміщення образу винуватця drawable-nodpiдля запобігання масштабування вирішило проблему.


3
У мене виникли проблеми з пам’яттю, намагаючись завантажити чернетки. Провели 2 години, намагаючись зрозуміти, чому це відбувається. Дякую за непряму відповідь.
TrueCoke

16
Це правильна відповідь і її слід позначити як таку.
wblaschko

3
Близько трьох з половиною місяців зараз я майже повною програмою працював на Android, і я зараз це зрозумів. Здається, німим зробити drawableпо суті приховану drawable-mdpiпапку. Це також пояснило, чому мої спеціальні маркери карт виглядали жахливо (вони були розширені, а потім зменшені).
theblang

10
так, до біса! Я думаю, що 99% андроїдських програмістів вважають, що «малювати» означає «не масштабувати це».
Метт Логан

3
Це найкорисніша відповідь, яку я коли-небудь бачив. Все, що я можу сказати, - я надсилаю щедроту! ДЯКУЮ.
Fattie

105

Я зменшив зображення таким чином:

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

2
дякую, createScaledBitmap був корисним для мене, щоб я міг показати занадто велику растрову карту
Хлопчик

Вирішив моє питання .. дякую. Насправді я знімав зображення з камери і відображався у ImageView у Samsung Galaxy S4 з 4.4.2
Мітеш Шах

вибачте, але я не можу виявити, що таке "w"
Боббелініо

1
Вибачте, що це ctxозначає?
Ameer Sabith

1
@AmeerSabith виглядає так, що ctx - це об'єкт контексту (наприклад, ваша запущена діяльність)
Метт,

34

Замість того, щоб витрачати години на години, намагаючись написати / відладкувати весь цей код зменшення тиску вручну, чому б не використати Picasso? Він був створений для роботи з bitmapsусіма типами та / або розмірами.

Я використовував цей єдиний рядок коду, щоб видалити проблему "занадто велика растрова карта ...."

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

Використання centerCrop () без виклику resize () призведе до IllegalStateException. Бібліотека змушує викликати розмір, коли використовується центральний обріз.
Zsolt Boldizsár

Це має ідеальний сенс, адже обрізка означає, що ви змінюєте розмір зображення.
Філео99

2
Швидке, легке і просте рішення. Не впевнений, чи це найкраще, але я отримав те, що хотів. Дуже дякую
Nabin

як і раніше отримують ту саму помилку, коли використовували ціль із Пікассо, для зображення великих розмірів :(
Нарендра Сінгх

Спробуйте використовувати версію 2.5.3-SNAPSHOT, здається, зараз правильно працювати з великими зображеннями
Антон Малмигін

20

Додавання наступних 2 атрибутів у ( AndroidManifest.xml) працювало для мене:

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

Це вирішило мою проблему на пристрої Samsung. Спасибі
Hitesh Bisht

16

Для мене працювала зміна файлу зображення в drawable-nodpiпапку з drawableпапки.


Це не дозволить Android намагатися автоматично масштабувати зображення на основі розмірів пристрою та щільності екрана; саме тому це рішення працює. Android намагатиметься автоматично масштабувати все, що є в drawableпапці.
Chris Cirefice

10

Я використовував Пікассо і мав ту ж проблему. зображення було занадто великим принаймні за розміром, шириною чи висотою. нарешті я знайшов тут рішення. ви можете зменшити масштаб зображення в залежності від розміру дисплея, а також зберегти співвідношення сторін:

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

6

BitmapRegionDecoder робить трюк.

Ви можете замінити onDraw(Canvas canvas), запустити нову нитку і декодувати область, видиму користувачеві.


5

Як вказує Ларчо, починаючи з рівня 10 API, ви можете використовувати BitmapRegionDecoderдля завантаження певних регіонів із зображення, і за допомогою цього ви зможете показати велике зображення у високій роздільній здатності, виділивши в пам'яті лише потрібні регіони. Нещодавно я розробив кришку, яка забезпечує візуалізацію великих зображень із керуванням жестами. Вихідний код та зразки доступні тут .


3

Перегляд рівня

Ви можете відключити апаратне прискорення для окремого перегляду під час виконання за допомогою наступного коду:

myView.setLayerType (View.LAYER_TYPE_SOFTWARE, null);


3

Я зіткнувся з тією ж проблемою, ось моє рішення. встановіть ширину зображення такою ж, як ширина екрана андроїда, а потім масштабуйте висоту

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. дайте мені знати, чи працює це для вас.


2

Зменшення зображення:

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. Як я розумію, вSampleSize приймають лише 2 значення.


як знати reqHeight та reqWidth? Я маю на увазі, чи потрібно нам це зафіксувати до статичного значення? чи ми можемо змінити ці пристрої wrt?
Прашант Деббадвар

2

Використовуйте бібліотеку Glide замість того, щоб безпосередньо завантажуватися в перегляд зображень

Glide: https://github.com/bumptech/glide

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

2
Використання Glide замість Пікассо допомогло. Здається, Glide
Johnny Five

1

Я спробував усі рішення, описані вище, один за одним, протягом багатьох годин, і жодне, здавалося, не спрацювало! Нарешті, я вирішив подивитися офіційний приклад щодо зйомки зображень за допомогою камери 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);
}

0

ПРИМІТКА ДЛЯ ТИХ, КОМИ ХОЧУТЬ ВСТАВИТИ Зображення МАЛОГО РОЗМІРУ:

Рішення Pilot_51 (переміщення зображень у drawable-nodpiпапку) працює, але є ще одна проблема: він створює зображення занадто малий на екрані , якщо зображення не змінюється в дуже великий (наприклад , 2000 х 3800) дозвіл , щоб відповідати екрану - то це робить ваше додаток важче .

РІШЕННЯ : вставте свої файли зображень drawable-hdpi- Це працювало як принадність для мене.


1
Ви просто маскуєте свою проблему із щільністю зображення. На апараті низької щільності ваші зображення будуть виглядати більше.
рвап

я також не думаю, що у рішення Pilot_51 є якісь проблеми, ви повинні використовувати відповідні розміри зображення відповідно до ваших потреб
Nilabja

0

Використовуючи правильну рисувальну підпапку, це вирішило для мене. Моє рішення полягало в тому , щоб замість папки, що перетягується, помістити моє зображення в повній роздільній здатності (1920x1200) у папку Dravable-xhdpi .

Я також помістив зменшене зображення (1280x800) у папку Dravable-hdpi .

Ці дві резолюції відповідають планшетам Nexus 7 2013 та 2012, які я програмую. Я також випробував розчин на деяких інших планшетах.


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

    }
}

Цей код - робота

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.