2012-06-16 14 views
49

Tengo un archivo de imagen URI, y quiero reducir su tamaño para subirlo. El tamaño del archivo de imagen inicial depende de un dispositivo móvil a otro (puede ser de 2MB, como puede ser 500KB), pero quiero que el tamaño final sea de aproximadamente 200KB, para que pueda cargarlo.
Por lo que leo, tengo (al menos) 2 opciones:Android - Reducir el tamaño del archivo de imagen

  • Uso BitmapFactory.Options.inSampleSize, a submuestra imagen original y obtener una imagen más pequeña;
  • Usando Bitmap.compress para comprimir la imagen que especifica la calidad de compresión.

¿Cuál es la mejor opción?


pensaba para cambiar el tamaño de la imagen inicialmente anchura/altura hasta el ancho o alto está por encima de 1000 píxeles (algo así como 1024x768 u otros), y luego comprimir la imagen con la disminución de la calidad hasta el tamaño del archivo es superior a 200 KB. He aquí un ejemplo:

int MAX_IMAGE_SIZE = 200 * 1024; // max final file size 
Bitmap bmpPic = BitmapFactory.decodeFile(fileUri.getPath()); 
if ((bmpPic.getWidth() >= 1024) && (bmpPic.getHeight() >= 1024)) { 
    BitmapFactory.Options bmpOptions = new BitmapFactory.Options(); 
    bmpOptions.inSampleSize = 1; 
    while ((bmpPic.getWidth() >= 1024) && (bmpPic.getHeight() >= 1024)) { 
     bmpOptions.inSampleSize++; 
     bmpPic = BitmapFactory.decodeFile(fileUri.getPath(), bmpOptions); 
    } 
    Log.d(TAG, "Resize: " + bmpOptions.inSampleSize); 
} 
int compressQuality = 104; // quality decreasing by 5 every loop. (start from 99) 
int streamLength = MAX_IMAGE_SIZE; 
while (streamLength >= MAX_IMAGE_SIZE) { 
    ByteArrayOutputStream bmpStream = new ByteArrayOutputStream(); 
    compressQuality -= 5; 
    Log.d(TAG, "Quality: " + compressQuality); 
    bmpPic.compress(Bitmap.CompressFormat.JPEG, compressQuality, bmpStream); 
    byte[] bmpPicByteArray = bmpStream.toByteArray(); 
    streamLength = bmpPicByteArray.length; 
    Log.d(TAG, "Size: " + streamLength); 
} 
try { 
    FileOutputStream bmpFile = new FileOutputStream(finalPath); 
    bmpPic.compress(Bitmap.CompressFormat.JPEG, compressQuality, bmpFile); 
    bmpFile.flush(); 
    bmpFile.close(); 
} catch (Exception e) { 
    Log.e(TAG, "Error on saving file"); 
} 

¿Hay una mejor manera de hacerlo? ¿Debo intentar seguir usando los 2 métodos o solo uno? Gracias

+0

si la imagen de origen png o jpg? –

+0

Imagen de fuente es JPG – KitKat

Respuesta

27

Usando Bitmap.compress() solo especifica el algoritmo de compresión y, por cierto, la operación de compresión lleva bastante tiempo. Si necesita jugar con tamaños para reducir la asignación de memoria para su imagen, es necesario usar la escala de su imagen usando Bitmap.Options, primero computando límites de mapa de bits y luego decodificándolo al tamaño especificado.

La mejor muestra que encontré en StackOverflow es this one.

+1

Mi primera idea fue iterar la escala de la imagen (usando 'inSampleSize') hasta que el archivo de imagen sea inferior a' MAX_IMAGE_SIZE' pero, dado que tengo que guardar mi mapa de bits en un archivo, tengo que usar 'Bitmap. compress() '(o tal vez hay diferentes maneras de guardarlo en un archivo?), y llamarlo dando 100% de calidad, la imagen es más grande que' MAX_IMAGE_SIZE', así que de todos modos debería iterar 'Bitmap.compress()' (decreciente calidad) hasta el tamaño del archivo <'MAX_IMAGE_SIZE'. Tal vez hay mejores soluciones? – KitKat

0

La mayor parte de las respuestas que encontré fueron sólo piezas que tenía que poner juntos para obtener un código de trabajo, que se publica a continuación

public void compressBitmap(File file, int sampleSize, int quality) { 
     try { 
      BitmapFactory.Options options = new BitmapFactory.Options(); 
      options.inSampleSize = sampleSize; 
      FileInputStream inputStream = new FileInputStream(file); 

      Bitmap selectedBitmap = BitmapFactory.decodeStream(inputStream, null, options); 
      inputStream.close(); 

      FileOutputStream outputStream = new FileOutputStream("location to save"); 
      selectedBitmap.compress(Bitmap.CompressFormat.JPEG, quality, outputStream); 
      outputStream.close(); 
      long lengthInKb = photo.length()/1024; //in kb 
      if (lengthInKb > SIZE_LIMIT) { 
       compressBitmap(file, (sampleSize*2), (quality/4)); 
      } 

      selectedBitmap.recycle(); 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
    } 

2 parámetros sampleSize y la calidad juega un papel importante

sampleSize se utiliza para submuestra la imagen original y devolver una imagen más pequeña, es decir
SampleSize == 4 devuelve una imagen que tiene 1/4 del ancho/alto del original.

la calidad se utiliza para indicar el compresor, el rango de entrada está entre 0-100. 0 significado compresa para tamaño pequeño, 100 significado comprimir para la calidad máxima

+0

Obviamente esto NO ES completo.La variable "foto" ni siquiera se declara localmente. Además, usa recursión, NO es una buena idea. – Shroud

+0

@Shroud por favor siéntase libre de editar y agregar las cosas que faltan, –

+0

@war_Hero: Recursión no es una buena Idea .. – Pawan

Cuestiones relacionadas