web-dev-qa-db-fra.com

Redimensionner un fichier bitmap volumineux en fichier de sortie mis à l'échelle sur Android

J'ai un gros bitmap (disons 3888x2592) dans un fichier. Maintenant, je veux redimensionner ce bitmap à 800x533 et le sauvegarder dans un autre fichier . Normalement, je mettrais à l'échelle le bitmap en appelant la méthode Bitmap.createBitmap, mais elle nécessite un bitmap source comme premier argument, ce que je ne peux pas fournir, L’image originale dans un objet Bitmap dépasserait évidemment la mémoire (voir ici , par exemple).

Je ne peux pas non plus lire le bitmap avec, par exemple, BitmapFactory.decodeFile(file, options), en fournissant un BitmapFactory.Options.inSampleSize, car je souhaite le redimensionner à la largeur et à la hauteur exactes. Utiliser inSampleSize redimensionnerait le bitmap à 972x648 (si j'utilise inSampleSize=4) ou à 778x518 (si j'utilise inSampleSize=5, ce qui n'est même pas une puissance de 2).

J'aimerais également éviter de lire l'image en utilisant inSampleSize avec, par exemple, 972x648 dans une première étape, puis de la redimensionner à exactement 800x533 dans une seconde étape, car la qualité serait médiocre par rapport à un redimensionnement direct de l'image d'origine.

Pour résumer ma question: Existe-t-il un moyen de lire un fichier image volumineux de 10 MP ou plus et de l'enregistrer dans un nouveau fichier image, redimensionné à une nouvelle largeur et une hauteur spécifiques, sans obtenir une exception OutOfMemory?

J'ai également essayé BitmapFactory.decodeFile(file, options) et réglé les valeurs Options.outHeight et Options.outWidth manuellement sur 800 et 533, mais cela ne fonctionne pas de cette façon.

201
Manuel

Non J'aimerais que quelqu'un me corrige, mais j'ai accepté l'approche de chargement/redimensionnement que vous avez essayée comme compromis.

Voici les étapes à suivre pour quiconque navigue:

  1. Calculez le maximum possible inSampleSize qui produit toujours une image plus grande que votre cible.
  2. Chargez l'image en utilisant BitmapFactory.decodeFile(file, options), en passant inSampleSize en tant qu'option.
  3. Redimensionnez aux dimensions souhaitées en utilisant Bitmap.createScaledBitmap().
140
Justin

Justin répond traduit en code (fonctionne parfaitement pour moi):

private Bitmap getBitmap(String path) {

Uri uri = getImageUri(path);
InputStream in = null;
try {
    final int IMAGE_MAX_SIZE = 1200000; // 1.2MP
    in = mContentResolver.openInputStream(uri);

    // Decode image size
    BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
    BitmapFactory.decodeStream(in, null, options);
    in.close();



    int scale = 1;
    while ((options.outWidth * options.outHeight) * (1 / Math.pow(scale, 2)) > 
          IMAGE_MAX_SIZE) {
       scale++;
    }
    Log.d(TAG, "scale = " + scale + ", orig-width: " + options.outWidth + ", 
       orig-height: " + options.outHeight);

    Bitmap resultBitmap = null;
    in = mContentResolver.openInputStream(uri);
    if (scale > 1) {
        scale--;
        // scale to max possible inSampleSize that still yields an image
        // larger than target
        options = new BitmapFactory.Options();
        options.inSampleSize = scale;
        resultBitmap = BitmapFactory.decodeStream(in, null, options);

        // resize to desired dimensions
        int height = resultBitmap.getHeight();
        int width = resultBitmap.getWidth();
        Log.d(TAG, "1th scale operation dimenions - width: " + width + ",
           height: " + height);

        double y = Math.sqrt(IMAGE_MAX_SIZE
                / (((double) width) / height));
        double x = (y / height) * width;

        Bitmap scaledBitmap = Bitmap.createScaledBitmap(resultBitmap, (int) x, 
           (int) y, true);
        resultBitmap.recycle();
        resultBitmap = scaledBitmap;

        System.gc();
    } else {
        resultBitmap = BitmapFactory.decodeStream(in);
    }
    in.close();

    Log.d(TAG, "bitmap size - width: " +resultBitmap.getWidth() + ", height: " + 
       resultBitmap.getHeight());
    return resultBitmap;
} catch (IOException e) {
    Log.e(TAG, e.getMessage(),e);
    return null;
}
90
Ofir

Ce sont les solutions 'combinées' de Mojo Risin et de Ofir. Cela vous donnera une image redimensionnée proportionnellement avec les limites de largeur maximale et de hauteur maximale.

  1. Il ne lit que les métadonnées pour obtenir la taille d'origine (options.inJustDecodeBounds)
  2. Il utilise un redimensionnement forcé pour économiser de la mémoire (itmap.createScaledBitmap)
  3. Il utilise une image redimensionnée avec précision sur la base du Bitamp approximatif créé précédemment.

Pour moi, il fonctionne bien sur des images de 5 mégapixels et ci-dessous.

try
{
    int inWidth = 0;
    int inHeight = 0;

    InputStream in = new FileInputStream(pathOfInputImage);

    // decode image size (decode metadata only, not the whole image)
    BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
    BitmapFactory.decodeStream(in, null, options);
    in.close();
    in = null;

    // save width and height
    inWidth = options.outWidth;
    inHeight = options.outHeight;

    // decode full image pre-resized
    in = new FileInputStream(pathOfInputImage);
    options = new BitmapFactory.Options();
    // calc rought re-size (this is no exact resize)
    options.inSampleSize = Math.max(inWidth/dstWidth, inHeight/dstHeight);
    // decode full image
    Bitmap roughBitmap = BitmapFactory.decodeStream(in, null, options);

    // calc exact destination size
    Matrix m = new Matrix();
    RectF inRect = new RectF(0, 0, roughBitmap.getWidth(), roughBitmap.getHeight());
    RectF outRect = new RectF(0, 0, dstWidth, dstHeight);
    m.setRectToRect(inRect, outRect, Matrix.ScaleToFit.CENTER);
    float[] values = new float[9];
    m.getValues(values);

    // resize bitmap
    Bitmap resizedBitmap = Bitmap.createScaledBitmap(roughBitmap, (int) (roughBitmap.getWidth() * values[0]), (int) (roughBitmap.getHeight() * values[4]), true);

    // save image
    try
    {
        FileOutputStream out = new FileOutputStream(pathOfOutputImage);
        resizedBitmap.compress(Bitmap.CompressFormat.JPEG, 80, out);
    }
    catch (Exception e)
    {
        Log.e("Image", e.getMessage(), e);
    }
}
catch (IOException e)
{
    Log.e("Image", e.getMessage(), e);
}
41
blubl

Pourquoi ne pas utiliser l'API?

int h = 48; // height in pixels
int w = 48; // width in pixels    
Bitmap scaled = Bitmap.createScaledBitmap(largeBitmap, w, h, true);
22
Bostone

Reconnaissant l’autre excellente réponse jusqu’à présent, le meilleur code que j’ai vu à ce jour se trouve dans la documentation de l’outil de prise de photos.

Voir la section intitulée "Décoder une image mise à l'échelle".

http://developer.Android.com/training/camera/photobasics.html

La solution proposée est une solution à redimensionner puis à l’échelle comme les autres ici, mais c’est assez chouette.

J'ai copié le code ci-dessous en tant que fonction prête à l'emploi pour plus de commodité.

private void setPic(String imagePath, ImageView destination) {
    int targetW = destination.getWidth();
    int targetH = destination.getHeight();
    // Get the dimensions of the bitmap
    BitmapFactory.Options bmOptions = new BitmapFactory.Options();
    bmOptions.inJustDecodeBounds = true;
    BitmapFactory.decodeFile(imagePath, bmOptions);
    int photoW = bmOptions.outWidth;
    int photoH = bmOptions.outHeight;

    // Determine how much to scale down the image
    int scaleFactor = Math.min(photoW/targetW, photoH/targetH);

    // Decode the image file into a Bitmap sized to fill the View
    bmOptions.inJustDecodeBounds = false;
    bmOptions.inSampleSize = scaleFactor;
    bmOptions.inPurgeable = true;

    Bitmap bitmap = BitmapFactory.decodeFile(imagePath, bmOptions);
    destination.setImageBitmap(bitmap);
}
19
Alex

Après avoir lu ces réponses et la documentation Android voici le code pour redimensionner le bitmap sans le charger en mémoire

public Bitmap getResizedBitmap(int targetW, int targetH,  String imagePath) {

    // Get the dimensions of the bitmap
    BitmapFactory.Options bmOptions = new BitmapFactory.Options();
    //inJustDecodeBounds = true <-- will not load the bitmap into memory
    bmOptions.inJustDecodeBounds = true;
    BitmapFactory.decodeFile(imagePath, bmOptions);
    int photoW = bmOptions.outWidth;
    int photoH = bmOptions.outHeight;

    // Determine how much to scale down the image
    int scaleFactor = Math.min(photoW/targetW, photoH/targetH);

    // Decode the image file into a Bitmap sized to fill the View
    bmOptions.inJustDecodeBounds = false;
    bmOptions.inSampleSize = scaleFactor;
    bmOptions.inPurgeable = true;

    Bitmap bitmap = BitmapFactory.decodeFile(imagePath, bmOptions);
    return(bitmap);
}
18
penduDev

Quand j'ai de grandes bitmaps et que je veux les décoder redimensionnées j'utilise

BitmapFactory.Options options = new BitmapFactory.Options();
InputStream is = null;
is = new FileInputStream(path_to_file);
BitmapFactory.decodeStream(is,null,options);
is.close();
is = new FileInputStream(path_to_file);
// here w and h are the desired width and height
options.inSampleSize = Math.max(options.outWidth/w, options.outHeight/h);
// bitmap is the resized bitmap
Bitmap bitmap = BitmapFactory.decodeStream(is,null,options);
5
Mojo Risin

Cela peut être utile pour quelqu'un d'autre regardant cette question. J'ai réécrit le code de Justin pour permettre à la méthode de recevoir également l'objet de taille cible requis. Cela fonctionne très bien lorsque vous utilisez Canvas. Tout le mérite devrait aller à JUSTIN pour son excellent code initial.

    private Bitmap getBitmap(int path, Canvas canvas) {

        Resources resource = null;
        try {
            final int IMAGE_MAX_SIZE = 1200000; // 1.2MP
            resource = getResources();

            // Decode image size
            BitmapFactory.Options options = new BitmapFactory.Options();
            options.inJustDecodeBounds = true;
            BitmapFactory.decodeResource(resource, path, options);

            int scale = 1;
            while ((options.outWidth * options.outHeight) * (1 / Math.pow(scale, 2)) > 
                  IMAGE_MAX_SIZE) {
               scale++;
            }
            Log.d("TAG", "scale = " + scale + ", orig-width: " + options.outWidth + ", orig-height: " + options.outHeight);

            Bitmap pic = null;
            if (scale > 1) {
                scale--;
                // scale to max possible inSampleSize that still yields an image
                // larger than target
                options = new BitmapFactory.Options();
                options.inSampleSize = scale;
                pic = BitmapFactory.decodeResource(resource, path, options);

                // resize to desired dimensions
                int height = canvas.getHeight();
                int width = canvas.getWidth();
                Log.d("TAG", "1th scale operation dimenions - width: " + width + ", height: " + height);

                double y = Math.sqrt(IMAGE_MAX_SIZE
                        / (((double) width) / height));
                double x = (y / height) * width;

                Bitmap scaledBitmap = Bitmap.createScaledBitmap(pic, (int) x, (int) y, true);
                pic.recycle();
                pic = scaledBitmap;

                System.gc();
            } else {
                pic = BitmapFactory.decodeResource(resource, path);
            }

            Log.d("TAG", "bitmap size - width: " +pic.getWidth() + ", height: " + pic.getHeight());
            return pic;
        } catch (Exception e) {
            Log.e("TAG", e.getMessage(),e);
            return null;
        }
    }

Le code de Justin est TRÈS efficace pour réduire les frais généraux liés au travail avec de grandes bitmaps. 

5
Music Monkey

Je ne sais pas si ma solution est la meilleure pratique, mais j'ai réussi à charger un bitmap avec la mise à l'échelle souhaitée en utilisant les options inDensity et inTargetDensity. inDensity est 0 initialement lorsque vous ne chargez pas de ressource pouvant être dessinée, cette approche sert donc à charger des images sans ressources.

Les variables imageUri, maxImageSideLength et context sont des paramètres de ma méthode. J'ai posté uniquement l'implémentation de la méthode sans le wrapper AsyncTask pour plus de clarté.

            ContentResolver resolver = context.getContentResolver();
            InputStream is;
            try {
                is = resolver.openInputStream(imageUri);
            } catch (FileNotFoundException e) {
                Log.e(TAG, "Image not found.", e);
                return null;
            }
            Options opts = new Options();
            opts.inJustDecodeBounds = true;
            BitmapFactory.decodeStream(is, null, opts);

            // scale the image
            float maxSideLength = maxImageSideLength;
            float scaleFactor = Math.min(maxSideLength / opts.outWidth, maxSideLength / opts.outHeight);
            // do not upscale!
            if (scaleFactor < 1) {
                opts.inDensity = 10000;
                opts.inTargetDensity = (int) ((float) opts.inDensity * scaleFactor);
            }
            opts.inJustDecodeBounds = false;

            try {
                is.close();
            } catch (IOException e) {
                // ignore
            }
            try {
                is = resolver.openInputStream(imageUri);
            } catch (FileNotFoundException e) {
                Log.e(TAG, "Image not found.", e);
                return null;
            }
            Bitmap bitmap = BitmapFactory.decodeStream(is, null, opts);
            try {
                is.close();
            } catch (IOException e) {
                // ignore
            }

            return bitmap;
4
cybergen

Compte tenu du fait que vous souhaitez redimensionner à la taille exacte et que vous souhaitez conserver autant de qualité que nécessaire, vous devriez essayer.

  1. Découvrez la taille de l'image redimensionnée avec l'appel de BitmapFactory.decodeFile et en fournissant le checkSizeOptions.inJustDecodeBounds
  2. Calculez le maximum possible dansSampleSize que vous pouvez utiliser sur votre appareil pour ne pas dépasser la mémoire. bitmapSizeInBytes = 2 * width * height; Généralement, pour votre image, inSampleSize = 2 conviendrait, car vous n’avez besoin que de 2 * 1944x1296) = 4,8 Mo, ce qui devrait rester dans la mémoire.
  3. Utilisez BitmapFactory.decodeFile avec inSampleSize pour charger le bitmap
  4. Ajustez le bitmap à la taille exacte. 

Motivation: la mise à l'échelle en plusieurs étapes peut vous donner une image de meilleure qualité. Cependant, rien ne garantit que cela fonctionnera mieux que d'utiliser une valeur inSampleSize élevée. En fait, je pense que vous pouvez également utiliser inSampleSize comme 5 (pas pow de 2) pour avoir une mise à l’échelle directe en une seule opération. Ou utilisez simplement 4 et vous pourrez alors utiliser cette image dans l'interface utilisateur. si vous l'envoyez au serveur, vous pouvez effectuer une mise à l'échelle à la taille exacte côté serveur, ce qui vous permet d'utiliser des techniques de mise à l'échelle avancées.

Remarques: si le bitmap chargé à l'étape 3 est au moins 4 fois plus grand (donc le 4 * targetWidth <width), vous pouvez probablement utiliser plusieurs redimensionnements pour obtenir une meilleure qualité. du moins, cela fonctionne en Java générique. Sous Android, vous n’avez pas la possibilité de spécifier l’interpolation utilisée pour la mise à l’échelle http://today.Java.net/pub/a/today/2007/ 04/03/périls-of-image-getscalededstance.html

2
Andrey Chorniy

Code ci-dessus fait un peu plus propre. Les InputStreams sont enfin fermés pour assurer leur fermeture:

*Remarque
Input: InputStream est, int w, int h
Sortie: bitmap

    try
    {

        final int inWidth;
        final int inHeight;

        final File tempFile = new File(temp, System.currentTimeMillis() + is.toString() + ".temp");

        {

            final FileOutputStream tempOut = new FileOutputStream(tempFile);

            StreamUtil.copyTo(is, tempOut);

            tempOut.close();

        }



        {

            final InputStream in = new FileInputStream(tempFile);
            final BitmapFactory.Options options = new BitmapFactory.Options();

            try {

                // decode image size (decode metadata only, not the whole image)
                options.inJustDecodeBounds = true;
                BitmapFactory.decodeStream(in, null, options);

            }
            finally {
                in.close();
            }

            // save width and height
            inWidth = options.outWidth;
            inHeight = options.outHeight;

        }

        final Bitmap roughBitmap;

        {

            // decode full image pre-resized
            final InputStream in = new FileInputStream(tempFile);

            try {

                final BitmapFactory.Options options = new BitmapFactory.Options();
                // calc rought re-size (this is no exact resize)
                options.inSampleSize = Math.max(inWidth/w, inHeight/h);
                // decode full image
                roughBitmap = BitmapFactory.decodeStream(in, null, options);

            }
            finally {
                in.close();
            }

            tempFile.delete();

        }

        float[] values = new float[9];

        {

            // calc exact destination size
            Matrix m = new Matrix();
            RectF inRect = new RectF(0, 0, roughBitmap.getWidth(), roughBitmap.getHeight());
            RectF outRect = new RectF(0, 0, w, h);
            m.setRectToRect(inRect, outRect, Matrix.ScaleToFit.CENTER);
            m.getValues(values);

        }

        // resize bitmap
        final Bitmap resizedBitmap = Bitmap.createScaledBitmap(roughBitmap, (int) (roughBitmap.getWidth() * values[0]), (int) (roughBitmap.getHeight() * values[4]), true);

        return resizedBitmap;

    }
    catch (IOException e) {

        logger.error("Error:" , e);
        throw new ResourceException("could not create bitmap");

    }
2
user1327738

J'ai utilisé un code comme celui-ci:

  String filePath=Environment.getExternalStorageDirectory()+"/test_image.jpg";
  BitmapFactory.Options options=new BitmapFactory.Options();
  InputStream is=new FileInputStream(filePath);
  BitmapFactory.decodeStream(is, null, options);
  is.close();
  is=new FileInputStream(filePath);
  // here w and h are the desired width and height
  options.inSampleSize=Math.max(options.outWidth/460, options.outHeight/288); //Max 460 x 288 is my desired...
  // bmp is the resized bitmap
  Bitmap bmp=BitmapFactory.decodeStream(is, null, options);
  is.close();
  Log.d(Constants.TAG, "Scaled bitmap bytes, "+bmp.getRowBytes()+", width:"+bmp.getWidth()+", height:"+bmp.getHeight());

J'ai essayé l'image originale est de 1230 x 1230, et bitmap dit est de 330 x 330.
Et si et essayé 2590 x 3849, je vais avoir OutOfMemoryError.

Je l'ai tracé, il jette toujours OutOfMemoryError sur la ligne "BitmapFactory.decodeStream (is, null, options);", si le bitmap d'origine est trop volumineux ...

2
RRTW

Voici un article qui adopte une approche différente du redimensionnement. Il tentera de charger le plus grand bitmap possible dans la mémoire en fonction de la mémoire disponible dans le processus, puis effectuera les transformations.

http://bricolsoftconsulting.com/2012/12/07/handling-large-images-on-Android/

1
Theo

Pour redimensionner l’image «correctement», sans sauter de pixels, vous devez vous connecter au décodeur d’image pour effectuer l’échantillonnage en aval ligne par ligne. Android (et la bibliothèque Skia qui la sous-tend) ne fournit pas de tels crochets, vous devez donc lancer le vôtre. En supposant que vous parlez des images JPEG, le mieux serait d’utiliser libjpeg directement, en C.

Compte tenu de la complexité du processus, l’utilisation du sous-échantillon en deux étapes, puis une redimensionnement est probablement préférable pour les applications de type prévisualisation d’image.

1
D0SBoots

Si vous souhaitez absolument redimensionner une étape, vous pouvez probablement charger le bitmap complet siAndroid:largeHeap = true, mais comme vous pouvez le constater, cela n’est pas vraiment conseillé.

De docs: Android: largeHeap Indiquez si les processus de votre application doivent être créés avec un grand tas de Dalvik. Ceci s'applique à tous les processus créés pour l'application. Cela ne s'applique qu'à la première application chargée dans un processus; Si vous utilisez un ID utilisateur partagé pour permettre à plusieurs applications d'utiliser un processus, elles doivent toutes utiliser cette option de manière cohérente, sans quoi elles auront des résultats imprévisibles. utilisation pour améliorer les performances. Cette activation ne garantit pas non plus une augmentation fixe de la mémoire disponible, car certains périphériques sont limités par leur mémoire totale disponible.

1
PSIXO

Cela a fonctionné pour moi. La fonction obtient un chemin vers un fichier sur la carte SD et renvoie un bitmap dans la taille maximale qui peut être affichée . Le code provient de Ofir avec quelques modifications, telles que le fichier image sur sd, à la place d'un Ressource. Objet d'affichage.

private Bitmap makeBitmap(String path) {

    try {
        final int IMAGE_MAX_SIZE = 1200000; // 1.2MP
        //resource = getResources();

        // Decode image size
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(path, options);

        int scale = 1;
        while ((options.outWidth * options.outHeight) * (1 / Math.pow(scale, 2)) >
                IMAGE_MAX_SIZE) {
            scale++;
        }
        Log.d("TAG", "scale = " + scale + ", orig-width: " + options.outWidth + ", orig-height: " + options.outHeight);

        Bitmap pic = null;
        if (scale > 1) {
            scale--;
            // scale to max possible inSampleSize that still yields an image
            // larger than target
            options = new BitmapFactory.Options();
            options.inSampleSize = scale;
            pic = BitmapFactory.decodeFile(path, options);

            // resize to desired dimensions

            Display display = getWindowManager().getDefaultDisplay();
            Point size = new Point();
            display.getSize(size);
            int width = size.y;
            int height = size.x;

            //int height = imageView.getHeight();
            //int width = imageView.getWidth();
            Log.d("TAG", "1th scale operation dimenions - width: " + width + ", height: " + height);

            double y = Math.sqrt(IMAGE_MAX_SIZE
                    / (((double) width) / height));
            double x = (y / height) * width;

            Bitmap scaledBitmap = Bitmap.createScaledBitmap(pic, (int) x, (int) y, true);
            pic.recycle();
            pic = scaledBitmap;

            System.gc();
        } else {
            pic = BitmapFactory.decodeFile(path);
        }

        Log.d("TAG", "bitmap size - width: " +pic.getWidth() + ", height: " + pic.getHeight());
        return pic;

    } catch (Exception e) {
        Log.e("TAG", e.getMessage(),e);
        return null;
    }

}
0
Penta

J'utilise Integer.numberOfLeadingZeros pour calculer la meilleure taille d'échantillon, de meilleures performances.

Code complet en kotlin:

@Throws(IOException::class)
fun File.decodeBitmap(options: BitmapFactory.Options): Bitmap? {
    return inputStream().use {
        BitmapFactory.decodeStream(it, null, options)
    }
}

@Throws(IOException::class)
fun File.decodeBitmapAtLeast(
        @androidx.annotation.IntRange(from = 1) width: Int,
        @androidx.annotation.IntRange(from = 1) height: Int
): Bitmap? {
    val options = BitmapFactory.Options()

    options.inJustDecodeBounds = true
    decodeBitmap(options)

    val ow = options.outWidth
    val oh = options.outHeight

    if (ow == -1 || oh == -1) return null

    val w = ow / width
    val h = oh / height

    if (w > 1 && h > 1) {
        val p = 31 - maxOf(Integer.numberOfLeadingZeros(w), Integer.numberOfLeadingZeros(h))
        options.inSampleSize = 1 shl maxOf(0, p)
    }
    options.inJustDecodeBounds = false
    return decodeBitmap(options)
}
0
lymoge

Voici le code que j'utilise et qui n’a aucun problème à décoder les grandes images en mémoire sur Android. J'ai été capable de décoder des images plus grandes que 20Mo tant que mes paramètres d'entrée sont autour de 1024x1024. Vous pouvez enregistrer le bitmap renvoyé dans un autre fichier. Sous cette méthode se trouve une autre méthode que j’utilise également pour redimensionner les images en une nouvelle image. N'hésitez pas à utiliser ce code comme bon vous semble.

/*****************************************************************************
 * public decode - decode the image into a Bitmap
 * 
 * @param xyDimension
 *            - The max XY Dimension before the image is scaled down - XY =
 *            1080x1080 and Image = 2000x2000 image will be scaled down to a
 *            value equal or less then set value.
 * @param bitmapConfig
 *            - Bitmap.Config Valid values = ( Bitmap.Config.ARGB_4444,
 *            Bitmap.Config.RGB_565, Bitmap.Config.ARGB_8888 )
 * 
 * @return Bitmap - Image - a value of "null" if there is an issue decoding
 *         image dimension
 * 
 * @throws FileNotFoundException
 *             - If the image has been removed while this operation is
 *             taking place
 */
public Bitmap decode( int xyDimension, Bitmap.Config bitmapConfig ) throws FileNotFoundException
{
    // The Bitmap to return given a Uri to a file
    Bitmap bitmap = null;
    File file = null;
    FileInputStream fis = null;
    InputStream in = null;

    // Try to decode the Uri
    try
    {
        // Initialize scale to no real scaling factor
        double scale = 1;

        // Get FileInputStream to get a FileDescriptor
        file = new File( this.imageUri.getPath() );

        fis = new FileInputStream( file );
        FileDescriptor fd = fis.getFD();

        // Get a BitmapFactory Options object
        BitmapFactory.Options o = new BitmapFactory.Options();

        // Decode only the image size
        o.inJustDecodeBounds = true;
        o.inPreferredConfig = bitmapConfig;

        // Decode to get Width & Height of image only
        BitmapFactory.decodeFileDescriptor( fd, null, o );
        BitmapFactory.decodeStream( null );

        if( o.outHeight > xyDimension || o.outWidth > xyDimension )
        {
            // Change the scale if the image is larger then desired image
            // max size
            scale = Math.pow( 2, (int) Math.round( Math.log( xyDimension / (double) Math.max( o.outHeight, o.outWidth ) ) / Math.log( 0.5 ) ) );
        }

        // Decode with inSampleSize scale will either be 1 or calculated value
        o.inJustDecodeBounds = false;
        o.inSampleSize = (int) scale;

        // Decode the Uri for real with the inSampleSize
        in = new BufferedInputStream( fis );
        bitmap = BitmapFactory.decodeStream( in, null, o );
    }
    catch( OutOfMemoryError e )
    {
        Log.e( DEBUG_TAG, "decode : OutOfMemoryError" );
        e.printStackTrace();
    }
    catch( NullPointerException e )
    {
        Log.e( DEBUG_TAG, "decode : NullPointerException" );
        e.printStackTrace();
    }
    catch( RuntimeException e )
    {
        Log.e( DEBUG_TAG, "decode : RuntimeException" );
        e.printStackTrace();
    }
    catch( FileNotFoundException e )
    {
        Log.e( DEBUG_TAG, "decode : FileNotFoundException" );
        e.printStackTrace();
    }
    catch( IOException e )
    {
        Log.e( DEBUG_TAG, "decode : IOException" );
        e.printStackTrace();
    }

    // Save memory
    file = null;
    fis = null;
    in = null;

    return bitmap;

} // decode

REMARQUE: les méthodes n'ont rien à voir les unes avec les autres, à l'exception des appels createScaledBitmap qui décodent la méthode ci-dessus. Remarque: la largeur et la hauteur peuvent changer par rapport à l'image d'origine.

/*****************************************************************************
 * public createScaledBitmap - Creates a new bitmap, scaled from an existing
 * bitmap.
 * 
 * @param dstWidth
 *            - Scale the width to this dimension
 * @param dstHeight
 *            - Scale the height to this dimension
 * @param xyDimension
 *            - The max XY Dimension before the original image is scaled
 *            down - XY = 1080x1080 and Image = 2000x2000 image will be
 *            scaled down to a value equal or less then set value.
 * @param bitmapConfig
 *            - Bitmap.Config Valid values = ( Bitmap.Config.ARGB_4444,
 *            Bitmap.Config.RGB_565, Bitmap.Config.ARGB_8888 )
 * 
 * @return Bitmap - Image scaled - a value of "null" if there is an issue
 * 
 */
public Bitmap createScaledBitmap( int dstWidth, int dstHeight, int xyDimension, Bitmap.Config bitmapConfig )
{
    Bitmap scaledBitmap = null;

    try
    {
        Bitmap bitmap = this.decode( xyDimension, bitmapConfig );

        // Create an empty Bitmap which will contain the new scaled bitmap
        // This scaled bitmap should be the size we want to scale the
        // original bitmap too
        scaledBitmap = Bitmap.createBitmap( dstWidth, dstHeight, bitmapConfig );

        float ratioX = dstWidth / (float) bitmap.getWidth();
        float ratioY = dstHeight / (float) bitmap.getHeight();
        float middleX = dstWidth / 2.0f;
        float middleY = dstHeight / 2.0f;

        // Used to for scaling the image
        Matrix scaleMatrix = new Matrix();
        scaleMatrix.setScale( ratioX, ratioY, middleX, middleY );

        // Used to do the work of scaling
        Canvas canvas = new Canvas( scaledBitmap );
        canvas.setMatrix( scaleMatrix );
        canvas.drawBitmap( bitmap, middleX - bitmap.getWidth() / 2, middleY - bitmap.getHeight() / 2, new Paint( Paint.FILTER_BITMAP_FLAG ) );
    }
    catch( IllegalArgumentException e )
    {
        Log.e( DEBUG_TAG, "createScaledBitmap : IllegalArgumentException" );
        e.printStackTrace();
    }
    catch( NullPointerException e )
    {
        Log.e( DEBUG_TAG, "createScaledBitmap : NullPointerException" );
        e.printStackTrace();
    }
    catch( FileNotFoundException e )
    {
        Log.e( DEBUG_TAG, "createScaledBitmap : FileNotFoundException" );
        e.printStackTrace();
    }

    return scaledBitmap;
} // End createScaledBitmap
0
user560663
 Bitmap yourBitmap;
 Bitmap resized = Bitmap.createScaledBitmap(yourBitmap, newWidth, newHeight, true);

ou:

 resized = Bitmap.createScaledBitmap(yourBitmap,(int)(yourBitmap.getWidth()*0.8), (int)(yourBitmap.getHeight()*0.8), true);
0
Vaishali Sutariya

Il existe un excellent article sur ce problème sur le site Web du développeur Android: Chargement efficace de bitmaps

0
Muzikant