/* * Copyright (c) 2015-present, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */ package com.facebook.imageutils; import android.annotation.SuppressLint; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.Build; import android.support.v4.util.Pools; import android.util.Pair; import com.facebook.common.internal.Preconditions; import java.io.ByteArrayInputStream; import java.io.InputStream; import java.nio.ByteBuffer; import javax.annotation.Nullable; /** * This class contains utility method for Bitmap */ public final class BitmapUtil { private static final int DECODE_BUFFER_SIZE = 16 * 1024; private static final int POOL_SIZE = 12; private static final Pools.SynchronizedPool<ByteBuffer> DECODE_BUFFERS = new Pools.SynchronizedPool<>(POOL_SIZE); /** * Bytes per pixel definitions */ public static final int ALPHA_8_BYTES_PER_PIXEL = 1; public static final int ARGB_4444_BYTES_PER_PIXEL = 2; public static final int ARGB_8888_BYTES_PER_PIXEL = 4; public static final int RGB_565_BYTES_PER_PIXEL = 2; public static final float MAX_BITMAP_SIZE = 2048f; /** * @return size in bytes of the underlying bitmap */ @SuppressLint("NewApi") public static int getSizeInBytes(@Nullable Bitmap bitmap) { if (bitmap == null) { return 0; } // There's a known issue in KitKat where getAllocationByteCount() can throw an NPE. This was // apparently fixed in MR1: http://bit.ly/1IvdRpd. So we do a version check here, and // catch any potential NPEs just to be safe. if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT) { try { return bitmap.getAllocationByteCount(); } catch (NullPointerException npe) { // Swallow exception and try fallbacks. } } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR1) { return bitmap.getByteCount(); } // Estimate for earlier platforms. return bitmap.getWidth() * bitmap.getRowBytes(); } /** * Decodes only the bounds of an image and returns its width and height or null if the size can't * be determined * @param bytes the input byte array of the image * @return dimensions of the image */ public static @Nullable Pair<Integer, Integer> decodeDimensions(byte[] bytes) { // wrapping with ByteArrayInputStream is cheap and we don't have duplicate implementation return decodeDimensions(new ByteArrayInputStream(bytes)); } /** * Decodes only the bounds of an image and returns its width and height or null if the size can't * be determined * @param is the InputStream containing the image data * @return dimensions of the image */ public static @Nullable Pair<Integer, Integer> decodeDimensions(InputStream is) { Preconditions.checkNotNull(is); ByteBuffer byteBuffer = DECODE_BUFFERS.acquire(); if (byteBuffer == null) { byteBuffer = ByteBuffer.allocate(DECODE_BUFFER_SIZE); } BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; try { options.inTempStorage = byteBuffer.array(); BitmapFactory.decodeStream(is, null, options); return (options.outWidth == -1 || options.outHeight == -1) ? null : new Pair(options.outWidth, options.outHeight); } finally { DECODE_BUFFERS.release(byteBuffer); } } /** * Returns the amount of bytes used by a pixel in a specific * {@link android.graphics.Bitmap.Config} * @param bitmapConfig the {@link android.graphics.Bitmap.Config} for which the size in byte * will be returned * @return */ public static int getPixelSizeForBitmapConfig(Bitmap.Config bitmapConfig) { switch (bitmapConfig) { case ARGB_8888: return ARGB_8888_BYTES_PER_PIXEL; case ALPHA_8: return ALPHA_8_BYTES_PER_PIXEL; case ARGB_4444: return ARGB_4444_BYTES_PER_PIXEL; case RGB_565: return RGB_565_BYTES_PER_PIXEL; } throw new UnsupportedOperationException("The provided Bitmap.Config is not supported"); } /** * Returns the size in byte of an image with specific size * and {@link android.graphics.Bitmap.Config} * @param width the width of the image * @param height the height of the image * @param bitmapConfig the {@link android.graphics.Bitmap.Config} for which the size in byte * will be returned * @return */ public static int getSizeInByteForBitmap(int width, int height, Bitmap.Config bitmapConfig) { return width * height * getPixelSizeForBitmapConfig(bitmapConfig); } }