Android - dimensione e comprima um bitmap
Eu estou trabalhando em um aplicativo Android, que tem recurso de captura de câmera e upload de fotos. Se o dispositivo tiver uma câmera de alta resolução, o tamanho da imagem capturada será muito grande (1 a 3 MB ou mais).
Como o aplicativo precisará fazer o upload dessa imagem para o servidor, eu preciso compactar a imagem antes de fazer o upload. Se a câmera capturou uma foto em resolução total de 1920x1080, por exemplo, a saída ideal é manter uma proporção de 16: 9 da imagem, comprimi-la para uma imagem de 640x360 para reduzir a qualidade da imagem e torná-la menor em bytes.
Aqui está o meu código (referenciado no 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;
}
O problema com o código acima é:
Não é possível manter a proporção, o código está forçando a imagem a ser redimensionada para 480x800. Se o usuário capturar uma imagem em outra proporção, a imagem não ficará boa após a compactação.Não funciona bem. O código sempre alterará o tamanho da imagem para 7990272 bytes, independentemente do tamanho original do arquivo. Se o tamanho da imagem original já é muito pequeno, ela ficará grande (meu resultado de teste tira uma foto da minha parede, que é praticamente monocromática):
Original image size is: 990092 bytes.
Compressed image size is 7990272 bytes
Estou perguntando se há uma sugestão de uma maneira melhor de compactar a foto para que ela possa ser carregada sem problemas?