Menú Cerrar

Redimensionado de Bitmap manteniendo la proporción

Redimensionar (o reescalar si te gustan las traducciones literales) imágenes en Android es muy sencillo pero hay que conocer las dimensiones definitivas. Estas dimensiones definitivas se tendrán que calcular siempre que la imagen no se ajuste, si por ejemplo quieres poner una imagen de fondo y sabes que el ancho es 480 y el alto 800 puede pasar que la imagen resultante quede mal. El como mantener la proporción es aplicable para todos los entornos gráficos, da igual el lenguaje.

Para redimensionar una imagen (Bitmap) en Android hay que utilizar Bitmap.createScaledBitmap(), el cuál devolverá el Bitmap redimensionado resultante. Este método necesita que se le proporcionen además del Bitmap original el ancho y el alto final:

Bitmap imagenOriginal = BitmapFactory.decodeResource(getResources(),R.drawable.imagen);

Bitmap imagenFinal = Bitmap.createScaledBitmap(imagenOriginal,480,800,false);

¿Qué pasa si por ejemplo las dimensiones de nuestra imagen original son  500 x 1000 pixeles? Hay imágenes que puede que importe poco, pero si por ejemplo la imagen es la foto de una cara o el dibujo de un robot humanoide puede quedar un resultado extrañamente achatado o estilizado. Arreglar esto es muy sencillo y como he dicho en la introducción es aplicable a cualquier entorno gráfico, aunque no sea Android. Hay que dividir una de las dimensiones por su equivalente de la imagen y después multiplicar el resultado por la otra dimensión de la imagen. Queda más claro viendo el código:

Bitmap imagenOriginal = BitmapFactory.decodeResource(getResources(),R.drawable.imagen);

// Dividimos el ancho final por el ancho de la imagen original
float proporcion = ancho / (float) imagenOriginal.getWidth();

// y después multiplicamos el resultado por la altura de la imagen original
// para conseguir la altura final
Bitmap imagenFinal = Bitmap.createScaledBitmap(imagenOriginal,ancho,(int) (imagenOriginal.getHeight() * proporcion),false);

Hay que aclarar que la variable proporcion podría ser declarada entero, ya que el parámetro pedido en el método es entero, pero necesitamos los decimales para la multiplicación por la altura de la imagen, por lo que se convierte a entero al final.

Es una sencilla regla de tres. Hay que aclarar que si la imagen original no tiene la misma proporción que el espacio donde se quiere poner, lo normal es que sobre un trozo de la imagen, que deberá ser recortada después de redimensionar o si es un fondo para el canvas, lo que sobre no será visible sin más código.

4 comentarios

  1. Didier Rojas

    Buenas muy buenos los consejos que das aca, tengo una duda , no quiero mostrar el resultado solo quiero tomar imagen o imagenes en la sd y poder guardarlas a menor escala en lo posible manteniendo la reslucion es esto posible ?

  2. David

    Hola Didier, no te se decir sobre la resolución, las imágenes para los juegos que he hecho no necesitan mucho más de 72ppp, alguna puede que 96ppp. Si la reescalas es de suponer que pierda calidad. Si la duda es sobre como guardarlas si que te puedo ayudar. Si tu objetivo es crear thumbs de las imágenes te aconsejo que no te preocupes por la resolución.

    Primero modificas el bitmap como necesites, después lo conviertes en un array de bytes y por último lo guardas en un archivo:

    // Con el bitmap «imagen» ya declarado y modificado:
    FileOutputStream fos;
    try {
    ByteArrayOutputStream stream = new ByteArrayOutputStream();
    imagen.compress(Bitmap.CompressFormat.PNG, 100, stream);
    byte[] bytesImagen = stream.toByteArray();

    fos = getContext().openFileOutput(nombreArchivo, Context.MODE_PRIVATE);
    fos.write(bytesImagen);
    fos.close();
    } catch (Exception e) {
    e.printStackTrace();
    }

    Este ejemplo es sobre como guardarlo una vez que ya lo hayas modificado a tu gusto. Si quieres guardarlo en la sd externa tendrás que añadir al manifiesto permisos de escritura:

    android.permission.WRITE_EXTERNAL_STORAGE

    Espero haberte ayudado o como mínimo darte alguna pista para conseguirlo.

  3. Gustavo

    Una correccion… si proporcion es una valor menor que 1, o sea 0.nnn, esta operacion : (int) proporcion, da 0, y da un error ya que alto deberia ser > 0.
    Conclusion: lo correcto es (int) (alto * proporcion)

Los comentarios están cerrados.