"Растровое изображение слишком большое для загрузки в текстуру"


я загружаю растровое изображение в ImageView и вижу эту ошибку. Я полагаю, что этот предел относится к ограничению размера для аппаратных текстур OpenGL (2048x2048). Изображение, которое мне нужно загрузить, - это изображение с Пинч-зумом высотой около 4000 пикселей.

Я попытался отключить аппаратное ускорение в манифесте, но без радости.

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

можно ли загрузить изображение размером более 2048 пикселей в ImageView?

17 138

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

изменение файла изображения к с 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);

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