web-dev-qa-db-fra.com

Android - Réduit la taille du fichier image

J'ai un fichier image URI et je souhaite réduire sa taille pour le télécharger. La taille initiale du fichier image dépend d'un mobile à l'autre (peut atteindre 2 Mo et 500 Ko), mais je souhaite une taille finale d'environ 200 Ko afin de pouvoir la télécharger.
D'après ce que j'ai lu, j'ai au moins 2 choix:

  • Utilisation de BitmapFactory.Options.inSampleSize pour sous-échantillonner l'image d'origine et obtenir une image plus petite.
  • Utilisation de Bitmap.compress pour compresser l'image en spécifiant la qualité de la compression.

Quel est le meilleur choix?


Je pensais initialement redimensionner la largeur/hauteur de l'image jusqu'à ce que largeur ou hauteur dépasse 1000px (environ 1024x768 ou autres), puis compresser l'image avec une qualité décroissante jusqu'à ce que la taille du fichier soit supérieure à 200 Ko. Voici un exemple:

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");
}

Y a-t-il une meilleure façon de le faire? Devrais-je essayer de continuer à utiliser les 2 méthodes ou une seule? Merci

54
KitKat

En utilisant Bitmap.compress(), vous spécifiez simplement l'algorithme de compression et, en conséquence, l'opération de compression prend assez de temps. Si vous devez jouer avec des tailles permettant de réduire l’allocation de mémoire pour votre image, vous devez utiliser la mise à l’échelle de votre image à l’aide de Bitmap.Options, calculez d'abord les limites d'un bitmap, puis décodez-le à la taille spécifiée.

Le meilleur échantillon que j'ai trouvé sur StackOverflow est celui-ci .

29
teoREtik

La plupart des réponses que j'ai trouvées étaient juste des morceaux que je devais assembler pour obtenir un code de travail, qui est affiché ci-dessous

 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 paramètres sampleSize et la qualité joue un rôle important

sampleSize est utilisé pour sous-échantillonner l'image d'origine et renvoyer une image plus petite, c'est-à-dire
SampleSize == 4 renvoie une image représentant 1/4 de la largeur/hauteur de l'original.

la qualité est utilisée pour suggérer le compresseur, la plage d'entrée est comprise entre 0 et 100. 0 signifie compresser pour une petite taille, 100 signifie compresser pour une qualité maximale

1
war_Hero

BitmapFactory.Options - Réduit la taille de l'image (en mémoire).

Bitmap.compress () - Réduit la taille de l'image (sur le disque).


Reportez-vous à ce lien pour plus d'informations sur l'utilisation des deux:https://Android.jlelse.eu/loading-large-bitmaps-efficiently-in-Android-66826cd4ad5

0
Ziad H.