Salva bitmap nella posizione


469

Sto lavorando a una funzione per scaricare un'immagine da un server Web, visualizzarla sullo schermo e, se l'utente desidera conservare l'immagine, salvarla sulla scheda SD in una determinata cartella. C'è un modo semplice per prendere una bitmap e salvarla sulla scheda SD in una cartella di mia scelta?

Il mio problema è che posso scaricare l'immagine, visualizzarla sullo schermo come Bitmap. L'unico modo in cui sono stato in grado di trovare per salvare un'immagine in una cartella specifica è utilizzare FileOutputStream, ma ciò richiede un array di byte. Non sono sicuro di come convertire (se questo è anche il modo giusto) da Bitmap a array di byte, quindi posso usare un FileOutputStream per scrivere i dati.

L'altra opzione che ho è usare MediaStore:

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

Che funziona benissimo per salvare su scheda SD, ma non consente di personalizzare la cartella.


Esattamente quello che sto facendo nella mia app. Scarico un grande server di moduli immagine per manipolarlo e carico la bitmap direttamente su un'immagine visualizzata tramite il mImage.setImageBitmap(_result.getBitmap());mio onTaskComplete()callback. Ora devo consentire agli utenti di salvare il file localmente se lo desiderano tramite il menu di scelta rapida a lungo. Dovrei essere in grado di utilizzare la soluzione di seguito. Quello che voglio sapere, però, hai scoperto un approccio migliore a questo?
cablato il

C'è un modo modo elegante di farlo qui: stackoverflow.com/questions/4263375/...
Chepech

Risposte:


921
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();
}

11
Ho anche compresso l'immagine ma al 100 percento e quando ottengo la mia immagine su tela è molto piccola. qualche ragione?
AZ_18

3
@Aizaz Questo non cambierà la dimensione dell'immagine, ma solo il formato e (potenzialmente) la qualità. Vale anche la pena notare che la qualità di compressione, 90nell'esempio sopra riportato non avrà alcun effetto quando si salva come PNG, ma farà la differenza per JPEG. Nel caso di un JPEG, puoi scegliere qualsiasi numero compreso tra 0 e 100.
Plowman

1
Va notato che il salvataggio in questo modo di .JPEG con una qualità del 100% salverà effettivamente un'immagine diversa rispetto all'originale sul web (richiederà almeno molto più spazio), considera un approccio alternativo.
Warpzit,

42
Si fa a avere a recompress? Voglio solo salvare l'immagine originale.
Hein du Plessis,

2
@HeinduPlessis Non è necessario ma probabilmente dovresti. Il salvataggio della bitmap non elaborata richiederà molto più spazio, a seconda del formato (ad esempio ARGB_4444 vs ARGB_8888).
Irwinb,

134

È necessario utilizzare il Bitmap.compress()metodo per salvare una bitmap come file. Comprimerà (se il formato utilizzato lo consente) l'immagine e la spinge in un OutputStream.

Ecco un esempio di un'istanza Bitmap ottenuta tramite getImageBitmap(myurl)quella che può essere compressa come JPEG con un tasso di compressione dell'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());

@JoaquinG c'è qualche motivo per cui fOut.flush()non è possibile ometterlo?
Niklas,

@Niklas Penso che tu possa omettere flush.
JoaquinG,

1
Dovresti cambiare la formulazione da "tasso di compressione dell'85%" a "tasso di qualità dell'85%" per una minore ambiguità. Interpreterei "tasso di compressione dell'85%" per indicare "15% di qualità", ma il parametro int di Bitmap.compressspecifica la qualità.
Tim Cooke,

puoi postare il metodogetImageBitmap(myurl)
Aashish

38
outStream = new FileOutputStream(file);

genererà un'eccezione senza autorizzazione in AndroidManifest.xml (almeno in os2.2):

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

10
Non se il tuo file absolutePath è un percorso interno?
Blundell,

24

All'interno 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();
}

7
lo stai chiamando "pippo.jpg" ma stai usando la compressione PNG
Ralphleon,

1
il formato compresso dovrebbe essere .JPEG se si desidera modificare la qualità della bitmap. La qualità non può essere modificata nel formato PNG.
Mustafa Güven

13

Alcuni formati, come PNG che è senza perdita, ignoreranno l'impostazione della qualità.


2
PNG è ancora un formato compresso. L'impostazione della qualità non modifica la qualità della compressione?
Tamás Barta,

Lo stato dei documenti (evidenziando da me): Suggerimento per il compressore, 0-100. 0 significato comprimere per dimensioni ridotte, 100 significato comprimere per massima qualità. Alcuni formati, come PNG che è senza perdita di dati, ignoreranno l'impostazione della qualità
Stephan Henningsen,

10

Ecco il codice di esempio per il salvataggio di bitmap su file:

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

Ora chiama questa funzione per salvare la bitmap nella memoria interna.

File newfile = savebitmap(bitmap);

Spero che ti possa aiutare. Buona vita di programmazione.


8
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) {

}

1
non è necessario svuotare outStream se lo si passa nel metodo 'comprimere'. quel metodo farà per te.
Dharam,

7

Perché non chiamare il Bitmap.compressmetodo con 100 (che suona come senza perdita di dati)?


Anche se viene ignorato, dovrebbe essere 100. Se un giorno il formato di compressione viene cambiato in un formato allentato, l'immagine corrisponderà più strettamente ad esso in modo lasco. Nota anche che se hai un codice che riassume questa chiamata, questo potrebbe essere più importante.
ddcruver,

2
Il 100% non è senza perdita di dati con JPEG, FWIW. Puoi verificarlo caricando e salvando ripetutamente la bitmap.

5

Vorrei anche salvare una foto. Ma il mio problema (?) È che voglio salvarlo da una bitmap che ho disegnato.

L'ho fatto così:

 @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();
            }

 }

il tuo metodo di salvataggio funziona solo per me .. dopo aver perso alcune ore .. grazie mille signore.
Mohammed Sufian,

5

Il modo in cui ho scoperto di inviare PNG e trasparenza.

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

Il valore 85 qui non ha senso in quanto PNG è senza perdita di dati. La documentazione dice: "Alcuni formati, come PNG che è senza perdita di dati, ignoreranno l'impostazione della qualità"
Minhaz,

2

Crea una miniatura del video per un video. Potrebbe restituire null se il video è danneggiato o il formato non è supportato.

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

Per salvare la tua bitmap in sdcard usa il seguente codice

Memorizza immagine

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

Per ottenere il percorso per l'archiviazione delle immagini

/** 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

Vuoi salvare Bitmap nella directory di tua scelta. Ho creato una libreria ImageWorker che consente all'utente di caricare, salvare e convertire immagini bitmap / drawable / base64.

SDK min - 14

Pre-requisito

  • Il salvataggio dei file richiederebbe l'autorizzazione WRITE_EXTERNAL_STORAGE.
  • Il recupero dei file richiederebbe l'autorizzazione READ_EXTERNAL_STORAGE.

Salvataggio di Bitmap / Drawable / Base64

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

Caricamento bitmap

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

Implementazione

Aggiungi dipendenze

In Grado a livello di progetto

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

In Grado a livello di applicazione

dependencies {
            implementation 'com.github.ihimanshurawat:ImageWorker:0.51'
    }

Puoi leggere di più su https://github.com/ihimanshurawat/ImageWorker/blob/master/README.md


1

Ehi, dai solo il nome a .bmp

Fai questo:

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**")

sembrerà che IM JUST FOOLING AROUND ma provalo una volta salvato in bmp foramt..Cheers


1

Assicurarsi che la directory sia stata creata prima di chiamare bitmap.compress:

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

1

Dopo Android 4.4 Kitkat, e dal 2017 la quota di Android 4.4 e meno è di circa il 20% e in diminuzione, non è possibile salvare su scheda SD utilizzando la Fileclasse e il getExternalStorageDirectory()metodo. Questo metodo restituisce la memoria interna del dispositivo e salva le immagini visibili a tutte le app. Puoi anche salvare immagini solo private nella tua app e da eliminare quando l'utente elimina la tua app con il openFileOutput()metodo.

A partire da Android 6.0, è possibile formattare la scheda SD come memoria interna ma solo privata sul dispositivo (se si formatta l'automobile SD come memoria interna, solo il dispositivo può accedere o visualizzarne il contenuto) È possibile salvare su quella scheda SD utilizzando altre risposte ma se si desidera utilizzare una scheda SD rimovibile, leggere la mia risposta di seguito.

È necessario utilizzare Storage Access Framework per ottenere il onActivityResultmetodo di attività uri in cartella per ottenere la cartella selezionata dall'utente e aggiungere l'autorizzazione persistente per recuperare per poter accedere alla cartella dopo che l'utente ha riavviato il dispositivo.

@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);

            }
        }
    }
}

Ora, salva la cartella di salvataggio nelle preferenze condivise per non chiedere all'utente di selezionare la cartella ogni volta che vuoi salvare un'immagine.

Dovresti usare la DocumentFileclasse per salvare l'immagine, no Fileoppure ParcelFileDescriptor, per maggiori informazioni puoi controllare questo thread per salvare l'immagine sulla scheda SD con compress(CompressFormat.JPEG, 100, out);metodo e DocumentFileclassi.


1

Alcuni nuovi dispositivi non salvano bitmap Quindi ho spiegato un po 'di più ..

assicurati di aver aggiunto sotto Autorizzazione

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

e crea un file xml sotto il xmlnome della cartella provider_paths.xml

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

e in AndroidManifest sotto

<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>

quindi chiama semplicemente 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();
    }

dove

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

e altri metodi

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

e

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

Hai qualche informazione in più error handling for PIE devices..e suppongo che la ricorsione in getOutputMediaFilepotrebbe essere un ciclo infinito se la soluzione alternativa non riesce.
Raimund Wege,

0

Salva Bitmap nella tua galleria senza comprimere.

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

-1

// | == | Crea un file PNG da Bitmap:

void devImjFylFnc(String pthAndFylTtlVar, Bitmap iptBmjVar)
{
    try
    {
        FileOutputStream fylBytWrtrVar = new FileOutputStream(pthAndFylTtlVar);
        iptBmjVar.compress(Bitmap.CompressFormat.PNG, 100, fylBytWrtrVar);
        fylBytWrtrVar.close();
    }
    catch (Exception errVar) { errVar.printStackTrace(); }
}

// | == | Ottieni Bimap dal file:

Bitmap getBmjFrmFylFnc(String pthAndFylTtlVar)
{
    return BitmapFactory.decodeFile(pthAndFylTtlVar);
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.