5

Как декодировать растровые изображения из каталога Asset в Android 7?BitmapFactory.decodeStream from Assets возвращает null на Android 7

Мое приложение работает на Android-версиях вплоть до Marshmallow. С Android 7 не удается загрузить изображения из каталога Asset.

Мой код:

private Bitmap getImage(String imagename) { 
    // Log.dd(logger, "AsyncImageLoader: " + ORDNER_IMAGES + imagename); 

    AssetManager asset = context.getAssets(); 
    InputStream is = null; 
    try { 
     is = asset.open(ORDNER_IMAGES + imagename); 
    } catch (IOException e) { 
     // Log.de(logger, "image konnte nicht gelesen werden: " + ORDNER_IMAGES + imagename); 
     return null; 
    } 


    // First decode with inJustDecodeBounds=true to check dimensions 
    final BitmapFactory.Options options = new BitmapFactory.Options(); 
    options.inJustDecodeBounds = true; 
    BitmapFactory.decodeStream(is, null, options); 

    // Calculate inSampleSize 
    options.inSampleSize = calculateInSampleSize(options, PW, PH); 

    // Decode bitmap with inSampleSize set 
    options.inJustDecodeBounds = false; 

    // Lesen des Bitmaps in der optimierten Groesse 
    return BitmapFactory.decodeStream(is, null, options); 

} 

В результате (только Android 7) BitmapFactory.decodeStream равна нулю. Он корректно работает с более старыми API-интерфейсами Android.

В режиме отладки я вижу следующее сообщение:

09-04 10: 10: 50.384 6274-6610/MYAPP D/Skia: --- SkAndroidCodec :: NewFromStream возвращенного нулевой

Может ли кто-нибудь сказать мне причину и как исправить кодировку?

Редактировать: Между тем я обнаружил, что удаление первого BitmapFactory.decodeStream с inJustDecodeBounds = true приводит к успешному BitmapFactory.decodeStream впоследствии с inJustDecodeBounds = false. Не знаете причину и не знаете, как заменить измерение размера растрового изображения.

+0

Я предполагаю, что ваша проблема особенно важна для вашего актива. Я только что протестировал [один из моих образцов книг] (https://github.com/commonsguy/cw-omnibus/tree/master/Bitmaps/InSampleSize), который загружает изображения из активов на Nexus 9 под управлением Android 7.0. Кажется, он работает нормально. – CommonsWare

ответ

8

Я думаю, что мы находимся в одной лодке. Моя команда застряла в этой проблеме какое-то время, как вы.

Возможно, проблема в BitmapFactory.cpp (https://android.googlesource.com/platform/frameworks/base.git/+/master/core/jni/android/graphics/BitmapFactory.cpp) В Android 7.0 был добавлен некоторый код и возникла проблема.

// Create the codec. 
NinePatchPeeker peeker; 
std::unique_ptr<SkAndroidCodec> codec(SkAndroidCodec::NewFromStream(streamDeleter.release(), &peeker)); 
if (!codec.get()) { 
    return nullObjectReturn("SkAndroidCodec::NewFromStream returned null"); 
} 

И я узнал, что метод BitmapFactory.decodeStream не создать растровое изображение после того, как мы установили inJustDecodeBounds=false, но когда я пытаюсь создать изображение без связанного декодирования. Это работает! Проблема в том, что BitmapOptions в том, что InputStream не обновляется, когда мы снова вызываем BitmapFactory.decodeStream.

Так сбросить, что InputStream, прежде чем снова расшифровывают

private Bitmap getBitmapFromAssets(Context context, String fileName, int width, int height) { 
    AssetManager asset = context.getAssets(); 
    InputStream is; 
    try { 
     is = asset.open(fileName); 
    } catch (IOException e) { 
     return null; 
    } 
    BitmapFactory.Options options = new BitmapFactory.Options(); 
    options.inJustDecodeBounds = true; 
    BitmapFactory.decodeStream(is, null, options); 
    try { 
     is.reset(); 
    } catch (IOException e) { 
     return null; 
    } 
    options.inSampleSize = calculateInSampleSize(options, width, height); 
    options.inJustDecodeBounds = false; 
    return BitmapFactory.decodeStream(is, null, options); 
} 

public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) { 
    final int height = options.outHeight; 
    final int width = options.outWidth; 
    int inSampleSize = 1; 

    if (height > reqHeight || width > reqWidth) { 
     final int halfHeight = height/2; 
     final int halfWidth = width/2; 
     while ((halfHeight/inSampleSize) >= reqHeight 
       && (halfWidth/inSampleSize) >= reqWidth) { 
      inSampleSize *= 2; 
     } 
    } 
    return inSampleSize; 
} 

Это похоже, что мы должны сбросить InputStream каждый раз, прежде чем использовать его.

+0

Это сделало трюк. Просто сбросьте InputStream. Спасибо за помощь. – Savari

+0

Я пробовал этот трюк, но я продолжаю получать сообщение «mark/reset not supported» IOException при вызове остального. Но я использую FileInputStream, потому что я пытаюсь загрузить растровое изображение с SD-карты. –

+0

Есть ли другой способ, кроме FileInputStream, чтобы открыть файл из хранилища? –

0

Если это кому-то помогает, я столкнулся с аналогичной проблемой, обновляя старый код, который ранее работал для изменения размеров изображений. Моя проблема была еще выше, где я читал данные из файла изображения. Я использовал IOUtils.toByteArray(Reader), который устарел. Я переключился на преобразование в массив байтов непосредственно из URI, и теперь он работает хорошо. Смотрите первые две строки resizeImage() ниже на примере этого нового метода (Остальная часть кода позволяет мне изменить размер изображения.)

public static Bitmap resizeImage(Uri imageUri, int targetWidth, int targetHeight) { 
    // Convert the image to a byte array 
    java.net.URI tempUri = new URI(uri.toString()); 
    byte[] imageData = IOUtils.toByteArray(tempUri); 

    // First decode with inJustDecodeBounds=true to check dimensions 
    BitmapFactory.Options options = new BitmapFactory.Options(); 
    options.inJustDecodeBounds = true; 
    BitmapFactory.decodeByteArray(imageData, 0, imageData.length, options); 

    // Calculate inSampleSize 
    options.inSampleSize = calculateInSampleSize(options, targetWidth, targetHeight); 

    // Decode bitmap with inSampleSize set 
    options.inJustDecodeBounds = false; 
    Bitmap reducedBitmap = BitmapFactory.decodeByteArray(imageData, 0, imageData.length, options); 
    Bitmap resizedBitmap = Bitmap.createScaledBitmap(reducedBitmap, targetWidth, targetHeight, false); 

    return resizedBitmap; 
} 

public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) { 
    // Raw height and width of image 
    final int height = options.outHeight; 
    final int width = options.outWidth; 
    int inSampleSize = 1; 

    if (height > reqHeight || width > reqWidth) { 
     final int halfHeight = height/2; 
     final int halfWidth = width/2; 

     // Calculate the largest inSampleSize value that is a 
     // power of 2 and keeps both height and width larger 
     // than the requested height and width. 
     while ((halfHeight/inSampleSize) > reqHeight 
       && (halfWidth/inSampleSize) > reqWidth) { 
      inSampleSize *= 2; 
     } 
    } 

    return inSampleSize; 
} 

 Смежные вопросы

  • Нет связанных вопросов^_^