2016-09-04 16 views
5

Jak odkodować bitmapy z katalogu zasobów w systemie Android 7?BitmapFactory.decodeStream z aktywów zwraca wartość null na urządzeniu z systemem Android 7

Moja aplikacja działa poprawnie w wersjach Androida do Marshmallow. W systemie Android 7 nie można załadować obrazów z katalogu zasobów.

mój kod:

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

} 

W wyniku (tylko Android 7) BitmapFactory.decodeStream jest null. Działa poprawnie ze starszymi interfejsami API Androida.

W trybie debugowania widzę następujący komunikat:

09-04: 10: 10: 50.384 6274-6610/myapp D/skia --- SkAndroidCodec :: NewFromStream zwrócony zerowej

Czy ktoś może mi powiedzieć, dlaczego i jak poprawić kodowanie?

Edycja: W międzyczasie znalazłem, że usunięcie pierwszego BitmapFactory.decodeStream z inJustDecodeBounds = true prowadzi do udanego BitmapFactory.decodeStream z inJustDecodeBounds = false. Nie znam przyczyny i nie wiem, jak zastąpić pomiar rozmiaru bitmapy.

+0

Domyślam się, że Twój problem dotyczy konkretnego zasobu. Właśnie przetestowałem [jedną z moich próbek książek] (https://github.com/commonsguy/cw-omnibus/tree/master/Bitmaps/InSampleSize), która ładuje obrazy z zasobów na Nexusie 9 z systemem Android 7.0. Wygląda na to, że działa dobrze. – CommonsWare

Odpowiedz

8

myślę, że jesteśmy w tej samej łodzi. Mój zespół przez jakiś czas tkwił w tym problemie jak ty.

Wydaje się być problem w BitmapFactory.cpp (https://android.googlesource.com/platform/frameworks/base.git/+/master/core/jni/android/graphics/BitmapFactory.cpp) Niektóre kod został dodany w systemie Android 7.0 i wystąpił problem.

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

I znalazłem się metodę BitmapFactory.decodeStream nie stworzyć bitmapę po ustawiamy inJustDecodeBounds=false ale gdy próbuję stworzyć bitmapę bez związanego dekodowania. To działa! Problem dotyczy BitmapOptions w tym, że InputStream nie aktualizuje się, gdy ponownie wywołaliśmy BitmapFactory.decodeStream.

Więc zresetować że InputStream przed dekodowanie ponownie

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

To wygląda musimy zresetować InputStream za każdym razem, przed ponownym użyciem go.

+0

To załatwiło sprawę. Po prostu resetowanie InputStream. Dziękuję za pomoc. – Savari

+0

Próbowałem tej sztuczki, ale wciąż otrzymuję "mark/reset nie jest obsługiwane" wyjątek IOException podczas wywoływania odpoczynku. Ale używam FileInputStream, bo próbuję załadować bitmapę z karty SD. –

+0

Czy istnieje inny sposób oprócz FileInputStream do otwarcia pliku z magazynu? –

0

Jeśli to pomoże każdemu, natknąłem się na podobny problem, aktualizując starszy kod, który wcześniej działał przy zmianie rozmiaru obrazów. Mój problem był dalej w górę stos, w którym czytałem dane z pliku obrazu. Użyłem IOUtils.toByteArray(Reader), który jest przestarzały. Przełączyłem się na konwersję do tablicy bajtów bezpośrednio z URI i teraz działa dobrze. Zobacz pierwsze dwie linie resizeImage() poniżej na przykładzie tej nowej metody (Reszta kodu pozwala mi zmienić rozmiar obrazu.)

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; 
} 
Powiązane problemy