Esta respuesta se resume en Cargar mapas de bits grandes de forma eficiente,
que explica cómo usar inSampleSize para cargar una versión de mapa de bits reducida.
En particular , los mapas de bits de preescalado explican los detalles de varios métodos, cómo combinarlos y cuáles son los más eficientes en memoria.
Hay tres formas dominantes de cambiar el tamaño de un mapa de bits en Android que tienen diferentes propiedades de memoria:
API createScaledBitmap
Esta API tomará un mapa de bits existente y creará un NUEVO mapa de bits con las dimensiones exactas que ha seleccionado.
En el lado positivo, puede obtener exactamente el tamaño de imagen que está buscando (independientemente de cómo se vea). Pero la desventaja es que esta API requiere un mapa de bits existente para funcionar . Lo que significa que la imagen tendría que cargarse, decodificarse y crearse un mapa de bits antes de poder crear una nueva versión más pequeña. Esto es ideal en términos de obtener sus dimensiones exactas, pero horrible en términos de sobrecarga de memoria adicional. Como tal, esto es una especie de factor decisivo para la mayoría de los desarrolladores de aplicaciones que tienden a ser conscientes de la memoria.
inSampleSize bandera
BitmapFactory.Options
tiene una propiedad inSampleSize
que cambiará el tamaño de su imagen mientras la decodifica, para evitar la necesidad de decodificar a un mapa de bits temporal. Este valor entero utilizado aquí cargará una imagen con un tamaño reducido 1 / x. Por ejemplo, establecer inSampleSize
en 2 devuelve una imagen que tiene la mitad del tamaño, y establecerlo en 4 devuelve una imagen que es 1/4 del tamaño. Básicamente, los tamaños de imagen siempre serán una potencia de dos más pequeños que el tamaño de la fuente.
Desde la perspectiva de la memoria, usar inSampleSize
es una operación realmente rápida. Efectivamente, solo decodificará cada X píxel de su imagen en su mapa de bits resultante. Sin inSampleSize
embargo, hay dos problemas principales :
No te da resoluciones exactas . Solo reduce el tamaño de su mapa de bits en una potencia de 2.
No produce un cambio de tamaño de la mejor calidad . La mayoría de los filtros de cambio de tamaño producen imágenes atractivas al leer bloques de píxeles y luego ponderarlos para producir el píxel redimensionado en cuestión. inSampleSize
evita todo esto con solo leer cada pocos píxeles. El resultado es bastante eficiente y con poca memoria, pero la calidad se ve afectada.
Si solo está lidiando con reducir su imagen en un tamaño de pow2 y el filtrado no es un problema, entonces no puede encontrar un método más eficiente en memoria (o rendimiento) que inSampleSize
.
Indicadores inScaled, inDensity, inTargetDensity
Si tiene que escalar una imagen a una dimensión que no es igual a una potencia de dos, entonces usted tendrá el inScaled
, inDensity
y inTargetDensity
banderas de BitmapOptions
. Cuando inScaled
se ha establecido la bandera, el sistema derivará el valor de escala para aplicar a su mapa de bits dividiendo el inTargetDensity
por los inDensity
valores.
mBitmapOptions.inScaled = true;
mBitmapOptions.inDensity = srcWidth;
mBitmapOptions.inTargetDensity = dstWidth;
// will load & resize the image to be 1/inSampleSize dimensions
mCurrentBitmap = BitmapFactory.decodeResources(getResources(),
mImageIDs, mBitmapOptions);
El uso de este método redimensionará su imagen y también le aplicará un 'filtro de cambio de tamaño', es decir, el resultado final se verá mejor porque se han tenido en cuenta algunas matemáticas adicionales durante el paso de cambio de tamaño. Pero tenga cuidado: ese paso de filtro adicional, requiere tiempo de procesamiento adicional y puede sumarse rápidamente para imágenes grandes, lo que resulta en cambios de tamaño lentos y asignaciones de memoria adicionales para el filtro en sí.
Por lo general, no es una buena idea aplicar esta técnica a una imagen que sea significativamente más grande que el tamaño deseado, debido a la sobrecarga de filtrado adicional.
Combinación mágica
Desde la perspectiva de la memoria y el rendimiento, puede combinar estas opciones para obtener los mejores resultados. (ajuste de la inSampleSize
, inScaled
, inDensity
y inTargetDensity
banderas)
inSampleSize
primero se aplicará a la imagen, llevándola a la siguiente potencia de dos MÁS GRANDE que su tamaño objetivo. Luego, inDensity
y inTargetDensity
se utilizan para escalar el resultado a las dimensiones exactas que desee, aplicando una operación de filtro para limpiar la imagen.
Combinar estos dos es una operación mucho más rápida, ya que el inSampleSize
paso reducirá la cantidad de píxeles que el paso basado en Densidad resultante necesitará para aplicar su filtro de cambio de tamaño.
mBitmapOptions.inScaled = true;
mBitmapOptions.inSampleSize = 4;
mBitmapOptions.inDensity = srcWidth;
mBitmapOptions.inTargetDensity = dstWidth * mBitmapOptions.inSampleSize;
// will load & resize the image to be 1/inSampleSize dimensions
mCurrentBitmap = BitmapFactory.decodeFile(fileName, mBitmapOptions);
Si necesita ajustar una imagen a dimensiones específicas y un filtrado más agradable, esta técnica es el mejor puente para obtener el tamaño correcto, pero se realiza en una operación rápida y con poca memoria.
Obtener las dimensiones de la imagen
Obtener el tamaño de la imagen sin decodificar la imagen completa Para cambiar el tamaño de su mapa de bits, necesitará conocer las dimensiones entrantes. Puede usar la inJustDecodeBounds
bandera para obtener las dimensiones de la imagen, sin necesidad de decodificar los datos de píxeles.
// Decode just the boundaries
mBitmapOptions.inJustDecodeBounds = true;
BitmapFactory.decodeFile(fileName, mBitmapOptions);
srcWidth = mBitmapOptions.outWidth;
srcHeight = mBitmapOptions.outHeight;
//now go resize the image to the size you want
Puede usar esta bandera para decodificar el tamaño primero y luego calcular los valores adecuados para escalar a su resolución objetivo.