miniaturas - Android cómo crear miniatura en tiempo de ejecución
como hacer miniaturas (9)
Tengo una imagen de gran tamaño. En tiempo de ejecución, quiero leer la imagen del almacenamiento y escalarla para que su peso y tamaño se reduzcan y pueda usarlo como una miniatura. Cuando un usuario hace clic en la miniatura, quiero mostrar la imagen de tamaño completo.
Aquí hay una solución más completa para reducir un mapa de bits a tamaño de miniatura. Se expande en la solución Bitmap.createScaledBitmap manteniendo la relación de aspecto de las imágenes y acolchándolas al mismo ancho para que se vean bien en un ListView.
Además, sería mejor hacer este escalado una vez y almacenar el mapa de bits resultante como un blob en su base de datos Sqlite. He incluido un fragmento sobre cómo convertir el mapa de bits a una matriz de bytes para este propósito.
public static final int THUMBNAIL_HEIGHT = 48;
public static final int THUMBNAIL_WIDTH = 66;
imageBitmap = BitmapFactory.decodeByteArray(mImageData, 0, mImageData.length);
Float width = new Float(imageBitmap.getWidth());
Float height = new Float(imageBitmap.getHeight());
Float ratio = width/height;
imageBitmap = Bitmap.createScaledBitmap(imageBitmap, (int)(THUMBNAIL_HEIGHT*ratio), THUMBNAIL_HEIGHT, false);
int padding = (THUMBNAIL_WIDTH - imageBitmap.getWidth())/2;
imageView.setPadding(padding, 0, padding, 0);
imageView.setImageBitmap(imageBitmap);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
imageBitmap.compress(Bitmap.CompressFormat.PNG, 100, baos);
byte[] byteArray = baos.toByteArray();
Encontré una manera fácil de hacer esto
Bitmap thumbnail = ThumbnailUtils.extractThumbnail(BitmapFactory.decodeFile(mPath),200,200)
Sintaxis
Bitmap thumbnail = ThumbnailUtils.extractThumbnail(Bitmap source,int width,int height)
O
usar la dependencia de Picasso
compilar ''com.squareup.picasso: picasso: 2.5.2''
Picasso.with(context)
.load("file:///android_asset/DvpvklR.png")
.resize(50, 50)
.into(imageView2);
Referencia Picasso
Esta respuesta se basa en la solución presentada en https://developer.android.com/topic/performance/graphics/load-bitmap.html (sin usar bibliotecas externas) con algunos cambios por mi parte para mejorar su funcionalidad y hacerla más práctica. .
Algunas notas sobre esta solución:
Se supone que desea mantener la relación de aspecto . En otras palabras:
finalWidth / finalHeight == sourceBitmap.getWidth() / sourceBitmap.getWidth()
(Independientemente de los problemas de conversión y redondeo)Se supone que tiene dos valores (
maxWidth
ymaxHeight
) que desea que cualquiera de las dimensiones de su mapa de bits final no exceda su valor correspondiente . En otras palabras:finalWidth <= maxWidth && finalHeight <= maxHeight
Así que
minRatio
se ha colocado como la base de los cálculos (ver la implementación). A MENOS la solución básica que ha colocado amaxRatio
como la base de los cálculos en tiempo real . Además, el cálculo deinSampleSize
ha sido mucho mejor (más lógica, breve y eficiente).Se supone que desea (al menos) que una de las dimensiones finales tenga exactamente el valor de su valor máximo correspondiente (cada una fue posible, considerando los supuestos anteriores) . En otras palabras:
finalWidth == maxWidth || finalHeight == maxHeight
El último paso adicional en comparación con la solución básica (
Bitmap.createScaledBitmap(...)
) es para esta restricción " exactamente ". La nota muy importante es que no debe dar este paso al principio (como la respuesta aceptada ), ¡debido a su consumo significativo de memoria en el caso de imágenes enormes!Es para decodificar un
file
. Puede cambiarlo como la solución básica para decodificar unresource
(o todo lo que admiteBitmapFactory
).
La implementación:
public static Bitmap decodeSampledBitmap(String pathName, int maxWidth, int maxHeight) {
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(pathName, options);
final float wRatio_inv = (float) options.outWidth / maxWidth,
hRatio_inv = (float) options.outHeight / maxHeight; // Working with inverse ratios is more comfortable
final int finalW, finalH, minRatio_inv /* = max{Ratio_inv} */;
if (wRatio_inv > hRatio_inv) {
minRatio_inv = (int) wRatio_inv;
finalW = maxWidth;
finalH = Math.round(options.outHeight / wRatio_inv);
} else {
minRatio_inv = (int) hRatio_inv;
finalH = maxHeight;
finalW = Math.round(options.outWidth / hRatio_inv);
}
options.inSampleSize = pow2Ceil(minRatio_inv); // pow2Ceil: A utility function that comes later
options.inJustDecodeBounds = false; // Decode bitmap with inSampleSize set
return Bitmap.createScaledBitmap(BitmapFactory.decodeFile(pathName, options),
finalW, finalH, true);
}
/**
* @return the largest power of 2 that is smaller than or equal to number.
* WARNING: return {0b1000000...000} for ZERO input.
*/
public static int pow2Ceil(int number) {
return 1 << -(Integer.numberOfLeadingZeros(number) + 1); // is equivalent to:
// return Integer.rotateRight(1, Integer.numberOfLeadingZeros(number) + 1);
}
Sample Usage, en caso de que tengas una imageView
con un valor determinado para layout_width
( match_parent
o un valor explícito) y un valor indeterminado para layout_height
( wrap_content
) y en su lugar un valor determinado para maxHeight
:
imageView.setImageBitmap(decodeSampledBitmap(filePath,
imageView.getWidth(), imageView.getMaxHeight()));
La mejor solución que encontré es la siguiente. Comparado con las otras soluciones, este no necesita cargar la imagen completa para crear una miniatura, ¡así que es más eficiente! Su límite es que no puede tener una miniatura con el ancho y la altura exactos, pero la solución lo más cerca posible.
File file = ...; // the image file
Options bitmapOptions = new Options();
bitmapOptions.inJustDecodeBounds = true; // obtain the size of the image, without loading it in memory
BitmapFactory.decodeFile(file.getAbsolutePath(), bitmapOptions);
// find the best scaling factor for the desired dimensions
int desiredWidth = 400;
int desiredHeight = 300;
float widthScale = (float)bitmapOptions.outWidth/desiredWidth;
float heightScale = (float)bitmapOptions.outHeight/desiredHeight;
float scale = Math.min(widthScale, heightScale);
int sampleSize = 1;
while (sampleSize < scale) {
sampleSize *= 2;
}
bitmapOptions.inSampleSize = sampleSize; // this value must be a power of 2,
// this is why you can not have an image scaled as you would like
bitmapOptions.inJustDecodeBounds = false; // now we want to load the image
// Let''s load just the part of the image necessary for creating the thumbnail, not the whole image
Bitmap thumbnail = BitmapFactory.decodeFile(file.getAbsolutePath(), bitmapOptions);
// Save the thumbnail
File thumbnailFile = ...;
FileOutputStream fos = new FileOutputStream(thumbnailFile);
thumbnail.compress(Bitmap.CompressFormat.JPEG, 90, fos);
fos.flush();
fos.close();
// Use the thumbail on an ImageView or recycle it!
thumbnail.recycle();
Mi solución
byte[] imageData = null;
try
{
final int THUMBNAIL_SIZE = 64;
FileInputStream fis = new FileInputStream(fileName);
Bitmap imageBitmap = BitmapFactory.decodeStream(fis);
imageBitmap = Bitmap.createScaledBitmap(imageBitmap, THUMBNAIL_SIZE, THUMBNAIL_SIZE, false);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
imageBitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);
imageData = baos.toByteArray();
}
catch(Exception ex) {
}
Prueba esto
Bitmap ThumbImage = ThumbnailUtils.extractThumbnail(BitmapFactory.decodeFile(imagePath), THUMBSIZE, THUMBSIZE);
Esta utilidad está disponible desde API_LEVEl 8. [Source]
Si desea un resultado de alta calidad, utilice la biblioteca [RapidDecoder] [1]. Es simple como sigue:
import rapid.decoder.BitmapDecoder;
...
Bitmap bitmap = BitmapDecoder.from(getResources(), R.drawable.image)
.scale(width, height)
.useBuiltInDecoder(true)
.decode();
No te olvides de usar el decodificador incorporado si deseas reducir la escala a menos del 50% y un resultado HQ.
Utilice BitmapFactory.decodeFile(...)
para obtener su objeto Bitmap
y BitmapFactory.decodeFile(...)
en un ImageView
con ImageView.setImageBitmap()
.
En ImageView
establezca las dimensiones del diseño en algo pequeño, por ejemplo:
android:layout_width="66dip" android:layout_height="48dip"
Agregue un onClickListener
a ImageView
e inicie una nueva actividad, donde visualiza la imagen en tamaño completo con
android:layout_width="wrap_content" android:layout_height="wrap_content"
o especifica un tamaño más grande.
/**
* Creates a centered bitmap of the desired size.
*
* @param source original bitmap source
* @param width targeted width
* @param height targeted height
* @param options options used during thumbnail extraction
*/
public static Bitmap extractThumbnail(
Bitmap source, int width, int height, int options) {
if (source == null) {
return null;
}
float scale;
if (source.getWidth() < source.getHeight()) {
scale = width / (float) source.getWidth();
} else {
scale = height / (float) source.getHeight();
}
Matrix matrix = new Matrix();
matrix.setScale(scale, scale);
Bitmap thumbnail = transform(matrix, source, width, height,
OPTIONS_SCALE_UP | options);
return thumbnail;
}