web-dev-qa-db-fra.com

Enregistrer l'image bitmap à l'emplacement

Je travaille sur une fonction permettant de télécharger une image à partir d'un serveur Web, de l'afficher à l'écran et, si l'utilisateur souhaite conserver l'image, de l'enregistrer sur la carte SD dans un certain dossier. Existe-t-il un moyen simple de prendre une bitmap et de la sauvegarder sur la carte SD dans le dossier de mon choix?

Mon problème est que je peux télécharger l'image, l'afficher à l'écran en tant que bitmap. Le seul moyen que j'ai pu trouver pour enregistrer une image dans un dossier particulier est d'utiliser FileOutputStream, mais cela nécessite un tableau d'octets. Je ne suis pas sûr de savoir comment convertir (si c'est même le bon moyen) de Bitmap en tableau d'octets, afin de pouvoir utiliser un FileOutputStream pour écrire les données.

Mon autre option est d’utiliser MediaStore:

MediaStore.Images.Media.insertImage(getContentResolver(), bm,
    barcodeNumber + ".jpg Card Image", barcodeNumber + ".jpg Card Image");

Ce qui fonctionne bien pour enregistrer sur une carte SD, mais ne vous permet pas de personnaliser le dossier.

424
Chrispix
try (FileOutputStream out = new FileOutputStream(filename)) {
    bmp.compress(Bitmap.CompressFormat.PNG, 100, out); // bmp is your Bitmap instance
    // PNG is a lossless format, the compression factor (100) is ignored
} catch (IOException e) {
    e.printStackTrace();
}
850
Ulrich Scheller

Vous devez utiliser la méthode Bitmap.compress() pour enregistrer une image bitmap en tant que fichier. Il va compresser (si le format utilisé le permet) votre image et le pousser dans un flux de sortie.

Voici un exemple d'instance Bitmap obtenue via getImageBitmap(myurl) pouvant être compressée au format JPEG avec un taux de compression de 85%:

// Assume block needs to be inside a Try/Catch block.
String path = Environment.getExternalStorageDirectory().toString();
OutputStream fOut = null;
Integer counter = 0;
File file = new File(path, "FitnessGirl"+counter+".jpg"); // the File to save , append increasing numeric counter to prevent files from getting overwritten.
fOut = new FileOutputStream(file);

Bitmap pictureBitmap = getImageBitmap(myurl); // obtaining the Bitmap
pictureBitmap.compress(Bitmap.CompressFormat.JPEG, 85, fOut); // saving the Bitmap to a file compressed as a JPEG with 85% compression rate
fOut.flush(); // Not really required
fOut.close(); // do not forget to close the stream

MediaStore.Images.Media.insertImage(getContentResolver(),file.getAbsolutePath(),file.getName(),file.getName());
128
JoaquinG
outStream = new FileOutputStream(file);

va lancer une exception sans permission dans AndroidManifest.xml (au moins dans os2.2):

<uses-permission Android:name="Android.permission.WRITE_EXTERNAL_STORAGE"/>
35
user996042

À l'intérieur onActivityResult:

String filename = "pippo.png";
File sd = Environment.getExternalStorageDirectory();
File dest = new File(sd, filename);

Bitmap bitmap = (Bitmap)data.getExtras().get("data");
try {
     FileOutputStream out = new FileOutputStream(dest);
     bitmap.compress(Bitmap.CompressFormat.PNG, 90, out);
     out.flush();
     out.close();
} catch (Exception e) {
     e.printStackTrace();
}
22
Alessandro

Certains formats, comme le format PNG sans perte, ignorent le paramètre de qualité.

13
shinydev

Pourquoi ne pas appeler la méthode Bitmap.compress avec 100 (ce qui semble être sans perte)?

8
TofuBeer
Bitmap bbicon;

bbicon=BitmapFactory.decodeResource(getResources(),R.drawable.bannerd10);
//ByteArrayOutputStream baosicon = new ByteArrayOutputStream();
//bbicon.compress(Bitmap.CompressFormat.PNG,0, baosicon);
//bicon=baosicon.toByteArray();

String extStorageDirectory = Environment.getExternalStorageDirectory().toString();
OutputStream outStream = null;
File file = new File(extStorageDirectory, "er.PNG");
try {
    outStream = new FileOutputStream(file);
    bbicon.compress(Bitmap.CompressFormat.PNG, 100, outStream);
    outStream.flush();
    outStream.close();
} catch(Exception e) {

}
8
Ashish Anand

Voici l'exemple de code pour enregistrer l'image bitmap dans un fichier:

public static File savebitmap(Bitmap bmp) throws IOException {
    ByteArrayOutputStream bytes = new ByteArrayOutputStream();
    bmp.compress(Bitmap.CompressFormat.JPEG, 60, bytes);
    File f = new File(Environment.getExternalStorageDirectory()
            + File.separator + "testimage.jpg");
    f.createNewFile();
    FileOutputStream fo = new FileOutputStream(f);
    fo.write(bytes.toByteArray());
    fo.close();
    return f;
}

Appelez maintenant cette fonction pour enregistrer le bitmap dans la mémoire interne.

File newfile = savebitmap(bitmap);

J'espère que cela vous aidera… .. Bonne vie en code. 

8
A-Droid Tech

Je voudrais aussi enregistrer une photo. Mais mon problème (?) Est que je veux l'enregistrer à partir d'un bitmap que ive dessiné. 

Je l'ai fait comme ça:

 @Override
 public boolean onOptionsItemSelected(MenuItem item) {
            switch (item.getItemId()) {
            case R.id.save_sign:      

                myView.save();
                break;

            }
            return false;    

    }

public void save() {
            String filename;
            Date date = new Date(0);
            SimpleDateFormat sdf = new SimpleDateFormat ("yyyyMMddHHmmss");
            filename =  sdf.format(date);

            try{
                 String path = Environment.getExternalStorageDirectory().toString();
                 OutputStream fOut = null;
                 File file = new File(path, "/DCIM/Signatures/"+filename+".jpg");
                 fOut = new FileOutputStream(file);

                 mBitmap.compress(Bitmap.CompressFormat.JPEG, 85, fOut);
                 fOut.flush();
                 fOut.close();

                 MediaStore.Images.Media.insertImage(getContentResolver()
                 ,file.getAbsolutePath(),file.getName(),file.getName());

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

 }
5
user511895

La façon dont j'ai trouvé d'envoyer PNG et la transparence.

String file_path = Environment.getExternalStorageDirectory().getAbsolutePath() +
                    "/CustomDir";
File dir = new File(file_path);
if(!dir.exists())
  dir.mkdirs();

String format = new SimpleDateFormat("yyyyMMddHHmmss",
       Java.util.Locale.getDefault()).format(new Date());

File file = new File(dir, format + ".png");
FileOutputStream fOut;
try {
        fOut = new FileOutputStream(file);
        yourbitmap.compress(Bitmap.CompressFormat.PNG, 85, fOut);
        fOut.flush();
        fOut.close();
     } catch (Exception e) {
        e.printStackTrace();
 }

Uri uri = Uri.fromFile(file);     
Intent intent = new Intent(Android.content.Intent.ACTION_SEND);
intent.setType("image/*");
intent.putExtra(Android.content.Intent.EXTRA_SUBJECT, "");
intent.putExtra(Android.content.Intent.EXTRA_TEXT, "");
intent.putExtra(Intent.EXTRA_STREAM, uri);

startActivity(Intent.createChooser(intent,"Sharing something")));
5
JulienGenoud

Créer une vignette vidéo pour une vidéo. Il peut renvoyer la valeur null si la vidéo est corrompue ou si le format n'est pas pris en charge.

private void makeVideoPreview() {
    Bitmap thumbnail = ThumbnailUtils.createVideoThumbnail(videoAbsolutePath, MediaStore.Images.Thumbnails.MINI_KIND);
    saveImage(thumbnail);
}

Pour enregistrer votre bitmap dans sdcard, utilisez le code suivant

Image de magasin

private void storeImage(Bitmap image) {
    File pictureFile = getOutputMediaFile();
    if (pictureFile == null) {
        Log.d(TAG,
                "Error creating media file, check storage permissions: ");// e.getMessage());
        return;
    } 
    try {
        FileOutputStream fos = new FileOutputStream(pictureFile);
        image.compress(Bitmap.CompressFormat.PNG, 90, fos);
        fos.close();
    } catch (FileNotFoundException e) {
        Log.d(TAG, "File not found: " + e.getMessage());
    } catch (IOException e) {
        Log.d(TAG, "Error accessing file: " + e.getMessage());
    }  
}

Obtenir le chemin pour le stockage d'images

/** Create a File for saving an image or video */
private  File getOutputMediaFile(){
    // To be safe, you should check that the SDCard is mounted
    // using Environment.getExternalStorageState() before doing this. 
    File mediaStorageDir = new File(Environment.getExternalStorageDirectory()
            + "/Android/data/"
            + getApplicationContext().getPackageName()
            + "/Files"); 

    // This location works best if you want the created images to be shared
    // between applications and persist after your app has been uninstalled.

    // Create the storage directory if it does not exist
    if (! mediaStorageDir.exists()){
        if (! mediaStorageDir.mkdirs()){
            return null;
        }
    } 
    // Create a media file name
    String timeStamp = new SimpleDateFormat("ddMMyyyy_HHmm").format(new Date());
    File mediaFile;
        String mImageName="MI_"+ timeStamp +".jpg";
        mediaFile = new File(mediaStorageDir.getPath() + File.separator + mImageName);  
    return mediaFile;
} 
2
MashukKhan

Assurez-vous que le répertoire est créé avant d'appeler bitmap.compress

new File(FileName.substring(0,FileName.lastIndexOf("/"))).mkdirs();
1
user5480949

Après Android 4.4 KitKat, et à partir de 2017, la part d'Android 4.4 et moins équivaut à environ 20% et moins, il n'est plus possible de sauvegarder sur une carte SD à l'aide de la méthode File class et getExternalStorageDirectory(). Cette méthode rend la mémoire interne de votre appareil et les images sauvegardées visibles pour chaque application. Vous pouvez également enregistrer des images uniquement privées dans votre application et les supprimer lorsque l'utilisateur supprime votre application avec la méthode openFileOutput()

À partir d’Android 6.0, vous pouvez formater votre carte SD en tant que mémoire interne, mais uniquement privée pour votre appareil. (Si vous formatez la voiture SD en tant que mémoire interne, seul votre appareil peut accéder à son contenu ou en voir le contenu.) Vous pouvez enregistrer sur cette carte SD avec son contenu. d’autres réponses, mais si vous souhaitez utiliser une carte SD amovible, lisez ma réponse ci-dessous.

Vous devez utiliser Storage Access Framework pour obtenir uri dans le dossier onActivityResult, méthode d’activité pour obtenir le dossier sélectionné par l’utilisateur, et ajoutez une autorisation de récupération persistante pour pouvoir accéder au dossier une fois que l’utilisateur a redémarré le périphérique.

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);

    if (resultCode == RESULT_OK) {

        // selectDirectory() invoked
        if (requestCode == REQUEST_FOLDER_ACCESS) {

            if (data.getData() != null) {
                Uri treeUri = data.getData();
                tvSAF.setText("Dir: " + data.getData().toString());
                currentFolder = treeUri.toString();
                saveCurrentFolderToPrefs();

                // grantUriPermission(getPackageName(), treeUri,
                // Intent.FLAG_GRANT_READ_URI_PERMISSION |
                // Intent.FLAG_GRANT_WRITE_URI_PERMISSION);

                final int takeFlags = data.getFlags()
                        & (Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
                // Check for the freshest data.
                getContentResolver().takePersistableUriPermission(treeUri, takeFlags);

            }
        }
    }
}

Enregistrez maintenant le dossier de sauvegarde dans les préférences partagées pour ne pas demander à l'utilisateur de sélectionner le dossier à chaque fois que vous souhaitez enregistrer une image.

Utilisez DocumentFile class pour enregistrer votre image et non File ou ParcelFileDescriptor. Pour plus d'informations, vous pouvez vérifier ce fil afin de sauvegarder l'image sur la carte SD avec la méthode compress(CompressFormat.JPEG, 100, out); et les classes DocumentFile.

1
Thracian

Vous voulez enregistrer Bitmap dans le répertoire de votre choix. J'ai créé une bibliothèque ImageWorker qui permet à l'utilisateur de charger, enregistrer et convertir des images bitmaps/drawables/base64.

Min SDK - 14

Prérequis 

  • L'enregistrement de fichiers nécessite l'autorisation WRITE_EXTERNAL_STORAGE.
  • La récupération de fichiers nécessiterait une autorisation READ_EXTERNAL_STORAGE.

Enregistrement de bitmap/Drawable/Base64

ImageWorker.to(context).
    directory("ImageWorker").
    subDirectory("SubDirectory").
    setFileName("Image").
    withExtension(Extension.PNG).
    save(sourceBitmap,85)

Chargement de bitmap

val bitmap: Bitmap? = ImageWorker.from(context).
    directory("ImageWorker").
    subDirectory("SubDirectory").
    setFileName("Image").
    withExtension(Extension.PNG).
    load()

La mise en oeuvre

Ajouter des dépendances

Au niveau du projet

allprojects {
        repositories {
            ...
            maven { url 'https://jitpack.io' }
        }
    }

Niveau d'application

dependencies {
            implementation 'com.github.1AboveAll:ImageWorker:0.51'
    }

Vous pouvez en savoir plus sur https://github.com/1AboveAll/ImageWorker/blob/master/README.md

1
Himanshu Rawat

Hé, donnez simplement le nom à .bmp

Faire ceci:

ByteArrayOutputStream bytes = new ByteArrayOutputStream();
_bitmapScaled.compress(Bitmap.CompressFormat.PNG, 40, bytes);

//you can create a new file name "test.BMP" in sdcard folder.
File f = new File(Environment.getExternalStorageDirectory()
                        + File.separator + "**test.bmp**")

ça va sembler que je viens de foutre dehors mais essayez-le une fois que ça sera enregistré en bmp foramt..Cheers

1
Mayank Saini

Pas vraiment une réponse, mais un commentaire. Je suis sur un Mac exécutant l'environnement de l'émulateur et j'obtiens une exception Java.io.IO: Autorisation refusée - erreur liée à ce code:

protected void onActivityResult(int requestCode, int resultCode, Intent imageReturnedIntent) {
    Log.d("DEBUG", "onActivityResult called");
    super.onActivityResult(requestCode, resultCode, imageReturnedIntent);
    if(requestCode == 0 && resultCode == RESULT_OK) {
        Log.d("DEBUG", "result is ok");
        try{
            Bitmap map = (Bitmap) imageReturnedIntent.getExtras().get("data");
            File sd = new File(Environment.getExternalStorageDirectory(), "test.png");
            sd.mkdirs();
            sd.createNewFile();
            FileOutputStream out = new FileOutputStream(sd);
            map.compress(Bitmap.CompressFormat.PNG, 90, out);
            out.flush();
            out.close();
        } catch(FileNotFoundException e){
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

J'ai également ajouté la propriété use-permission Android.permission.WRITE_EXTERNAL_STORAGE au fichier manifeste (comme indiqué par d'autres). 

0
stian

Enregistrer le bitmap dans votre galerie sans compresse.

private File saveBitMap(Context context, Bitmap Final_bitmap) {
    File pictureFileDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "Your Folder Name");
    if (!pictureFileDir.exists()) {
        boolean isDirectoryCreated = pictureFileDir.mkdirs();
        if (!isDirectoryCreated)
            Log.i("TAG", "Can't create directory to save the image");
        return null;
    }
    String filename = pictureFileDir.getPath() + File.separator + System.currentTimeMillis() + ".jpg";
    File pictureFile = new File(filename);
    try {
        pictureFile.createNewFile();
        FileOutputStream oStream = new FileOutputStream(pictureFile);
        Final_bitmap.compress(Bitmap.CompressFormat.PNG, 100, oStream);
        oStream.flush();
        oStream.close();
        Toast.makeText(Full_Screen_Activity.this, "Save Image Successfully..", Toast.LENGTH_SHORT).show();
    } catch (IOException e) {
        e.printStackTrace();
        Log.i("TAG", "There was an issue saving the image.");
    }
    scanGallery(context, pictureFile.getAbsolutePath());
    return pictureFile;
}
private void scanGallery(Context cntx, String path) {
    try {
        MediaScannerConnection.scanFile(cntx, new String[]{path}, null, new MediaScannerConnection.OnScanCompletedListener() {
            public void onScanCompleted(String path, Uri uri) {
                Toast.makeText(Full_Screen_Activity.this, "Save Image Successfully..", Toast.LENGTH_SHORT).show();
            }
        });
    } catch (Exception e) {
        e.printStackTrace();
        Log.i("TAG", "There was an issue scanning gallery.");
    }
}
0
Bhavik Nathani

Certains nouveaux périphériques ne sauvegardent pas les images bitmap. J'ai donc expliqué un peu plus.

assurez-vous que vous avez ajouté ci-dessous Permission

<uses-permission Android:name="Android.permission.WRITE_EXTERNAL_STORAGE" />

et créez un fichier xml sous le nom de dossier xml provider_paths.xml  

<?xml version="1.0" encoding="utf-8"?>
<paths>
    <external-path
        name="external_files"
        path="." />
</paths>

et dans AndroidManifest sous

<provider
            Android:name="Android.support.v4.content.FileProvider"
            Android:authorities="${applicationId}.provider"
            Android:exported="false"
            Android:grantUriPermissions="true">
            <meta-data
                Android:name="Android.support.FILE_PROVIDER_PATHS"
                Android:resource="@xml/provider_paths"/>
        </provider>

puis appelez simplement saveBitmapFile (passYourBitmapHere)

public static void saveBitmapFile(Bitmap bitmap) throws IOException {
        File mediaFile = getOutputMediaFile();
        FileOutputStream fileOutputStream = new FileOutputStream(mediaFile);
        bitmap.compress(Bitmap.CompressFormat.JPEG, getQualityNumber(bitmap), fileOutputStream);
        fileOutputStream.flush();
        fileOutputStream.close();
    }

File getOutputMediaFile() {
        File mediaStorageDir = new File(
                Environment.getExternalStorageDirectory(),
                "easyTouchPro");
        if (mediaStorageDir.isDirectory()) {

            // Create a media file name
            String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss")
                    .format(Calendar.getInstance().getTime());
            String mCurrentPath = mediaStorageDir.getPath() + File.separator
                            + "IMG_" + timeStamp + ".jpg";
            File mediaFile = new File(mCurrentPath);
            return mediaFile;
        } else { /// error handling for PIE devices..
            mediaStorageDir.delete();
            mediaStorageDir.mkdirs();
            galleryAddPic(mediaStorageDir);

            return (getOutputMediaFile());
        }
    }

et d'autres méthodes

public static int getQualityNumber(Bitmap bitmap) {
        int size = bitmap.getByteCount();
        int percentage = 0;

        if (size > 500000 && size <= 800000) {
            percentage = 15;
        } else if (size > 800000 && size <= 1000000) {
            percentage = 20;
        } else if (size > 1000000 && size <= 1500000) {
            percentage = 25;
        } else if (size > 1500000 && size <= 2500000) {
            percentage = 27;
        } else if (size > 2500000 && size <= 3500000) {
            percentage = 30;
        } else if (size > 3500000 && size <= 4000000) {
            percentage = 40;
        } else if (size > 4000000 && size <= 5000000) {
            percentage = 50;
        } else if (size > 5000000) {
            percentage = 75;
        }

        return percentage;
    }

et

void galleryAddPic(File f) {
        Intent mediaScanIntent = new Intent(
                "Android.intent.action.MEDIA_SCANNER_SCAN_FILE");
        Uri contentUri = Uri.fromFile(f);
        mediaScanIntent.setData(contentUri);

        this.sendBroadcast(mediaScanIntent);
    }
0
Xar E Ahmer