Android - Escala y comprime un mapa de bits
Estoy trabajando en una aplicación de Android, que tiene la función de captura de cámara y carga de fotos. Si el dispositivo tiene una cámara de alta resolución, el tamaño de la imagen capturada será realmente grande (1 ~ 3MB o más).
Dado que la aplicación necesitará cargar esta imagen al servidor, tendré que comprimir la imagen antes de cargarla. Si la cámara capturó una foto de resolución completa de 1920x1080, por ejemplo, la salida ideal es mantener una relación 16: 9 de la imagen, comprimirla para que sea una imagen de 640x360 para reducir la calidad de la imagen y hacerla más pequeña en bytes.
Aquí está mi código (referenciado de google):
/**
* this class provide methods that can help compress the image size.
*
*/
public class ImageCompressHelper {
/**
* Calcuate how much to compress the image
* @param options
* @param reqWidth
* @param reqHeight
* @return
*/
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;
}
/**
* resize image to 480x800
* @param filePath
* @return
*/
public static Bitmap getSmallBitmap(String filePath) {
File file = new File(filePath);
long originalSize = file.length();
MyLogger.Verbose("Original image size is: " + originalSize + " bytes.");
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(filePath, options);
// Calculate inSampleSize based on a preset ratio
options.inSampleSize = calculateInSampleSize(options, 480, 800);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
Bitmap compressedImage = BitmapFactory.decodeFile(filePath, options);
MyLogger.Verbose("Compressed image size is " + sizeOf(compressedImage) + " bytes");
return compressedImage;
}
El problema con el código anterior es:
No puede mantener la proporción, el código está forzando el tamaño de la imagen a 480x800. Si el usuario capturó una imagen en otra proporción, la imagen no se verá bien después de comprimir.No funciona bien. El código siempre cambiará el tamaño de la imagen a 7990272byte sin importar cuál sea el tamaño del archivo original. Si el tamaño de la imagen original ya es bastante pequeño, lo hará grande (el resultado de mi prueba para tomar una fotografía de mi muro, que es prácticamente de un solo color):
Original image size is: 990092 bytes.
Compressed image size is 7990272 bytes
Estoy preguntando si hay una sugerencia de una mejor manera de comprimir la foto para que se pueda cargar sin problemas.