Simpan bitmap ke lokasi


469

Saya sedang mengerjakan fungsi untuk mengunduh gambar dari server web, menampilkannya di layar, dan jika pengguna ingin menyimpan gambar, simpan di kartu SD di folder tertentu. Apakah ada cara mudah untuk mengambil bitmap dan hanya menyimpannya ke kartu SD di folder pilihan saya?

Masalah saya adalah saya bisa mengunduh gambar, menampilkannya di layar sebagai Bitmap. Satu-satunya cara saya dapat menemukan untuk menyimpan gambar ke folder tertentu adalah dengan menggunakan FileOutputStream, tetapi itu membutuhkan array byte. Saya tidak yakin bagaimana mengkonversi (jika ini adalah cara yang benar) dari Bitmap ke byte array, jadi saya dapat menggunakan FileOutputStream untuk menulis data.

Opsi lain yang saya miliki adalah menggunakan MediaStore:

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

Yang berfungsi baik untuk menyimpan ke kartu SD, tetapi tidak memungkinkan Anda untuk menyesuaikan folder.


Persis apa yang saya lakukan di aplikasi saya. Saya mengunduh bentuk server web gambar besar memanipulasi dan memuat bitmap langsung ke imageview melalui mImage.setImageBitmap(_result.getBitmap());di onTaskComplete()callback saya . Saya sekarang harus mengizinkan pengguna untuk menyimpan file secara lokal jika mereka mau melalui menu konteks pers yang panjang. Saya harus dapat menggunakan solusi di bawah ini. Apa yang ingin saya ketahui, apakah Anda menemukan pendekatan yang lebih baik untuk ini?
wired00

Ada cara yang elegan untuk melakukannya di sini: stackoverflow.com/questions/4263375/…
Chepech

Jawaban:


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
Saya juga telah mengompresi gambar tetapi hingga 100 persen dan ketika saya mendapatkan gambar saya di kanvas itu sangat kecil. alasan apapun?
AZ_

3
@ Aziz Ini tidak akan mengubah ukuran gambar, hanya format dan kualitas (berpotensi). Perlu juga dicatat bahwa kualitas kompresi 90, dalam contoh di atas tidak akan berpengaruh ketika menyimpan sebagai PNG, tetapi akan membuat perbedaan untuk JPEG. Dalam kasus JPEG, Anda dapat memilih angka apa saja antara 0 dan 100.
bajak

1
Perlu dicatat bahwa menyimpan cara ini untuk. JPEG dengan kualitas 100% benar-benar akan menyimpan gambar yang berbeda dari aslinya di web (setidaknya akan mengambil lebih banyak ruang), Pertimbangkan pendekatan alternatif.
Warpzit

42
Apakah kita harus mengkompres ulang? Saya hanya ingin menyimpan gambar asli.
Hein du Plessis

2
@HeinduPlessis Tidak harus tetapi Anda mungkin harus. Menyimpan bitmap mentah akan membutuhkan lebih banyak ruang, tergantung pada format (misalnya ARGB_4444 vs ARGB_8888).
irwinb

134

Anda harus menggunakan Bitmap.compress()metode ini untuk menyimpan Bitmap sebagai file. Ini akan memampatkan (jika format yang digunakan memungkinkannya) gambar Anda dan mendorongnya ke OutputStream.

Berikut adalah contoh instance Bitmap yang diperoleh getImageBitmap(myurl)yang dapat dikompresi sebagai JPEG dengan tingkat kompresi 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());

@ JoToquinG ada alasan untuk itu fOut.flush()tidak mungkin untuk menghilangkannya?
Niklas

@ Nikik Saya pikir Anda dapat menghilangkan flush.
JoaquinG

1
Anda harus mengubah kata-kata dari "tingkat kompresi 85%" menjadi "tingkat kualitas 85%" untuk lebih sedikit ambiguitas. Saya akan menafsirkan "tingkat kompresi 85%" berarti "kualitas 15%," tetapi parameter int Bitmap.compressmenentukan kualitas.
Tim Cooke

dapatkah Anda memposting metodegetImageBitmap(myurl)
Aashish

38
outStream = new FileOutputStream(file);

akan melempar pengecualian tanpa izin di AndroidManifest.xml (setidaknya di os2.2):

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

10
Tidak jika file absolutePath Anda adalah jalur internal?
Blundell

24

Di dalam 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
Anda menyebutnya "pippo.jpg" tetapi Anda menggunakan kompresi PNG
Ralphleon

1
format kompres harus. JPEG jika Anda ingin mengubah kualitas bitmap. Kualitas tidak dapat diubah dalam format PNG.
Mustafa Güven

13

Beberapa format, seperti PNG yang lossless, akan mengabaikan pengaturan kualitas.


2
PNG masih merupakan format terkompresi. Apakah pengaturan kualitas tidak mengubah kualitas kompresi?
Tamás Barta

Status dokumen (disoroti oleh saya): Petunjuk ke kompresor, 0-100. 0 kompres artinya untuk ukuran kecil, 100 kompres artinya untuk kualitas maks. Beberapa format, seperti PNG yang lossless, akan mengabaikan pengaturan kualitas
Stephan Henningsen

10

Berikut adalah contoh kode untuk menyimpan bitmap ke 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;
}

Sekarang panggil fungsi ini untuk menyimpan bitmap ke memori internal.

File newfile = savebitmap(bitmap);

Saya harap ini akan membantu Anda. Kehidupan kode yang menyenangkan.


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
Anda tidak perlu menyiram outStream jika Anda menggunakan metode 'kompres'. metode itu akan dilakukan atas nama Anda.
Dharam

7

Mengapa tidak memanggil Bitmap.compressmetode dengan 100 (yang kedengarannya seperti lossless)?


Meskipun diabaikan itu harus 100. Jika suatu hari format kompres diubah menjadi longgar maka gambar akan paling cocok dengan longgar. Perhatikan juga jika Anda memiliki kode yang mengabstraksikan panggilan ini, ini mungkin lebih penting.
ddcruver

2
100% tidak rugi dengan JPEG, FWIW. Anda dapat memverifikasi ini dengan memuat dan menyimpan bitmap berulang kali.

5

Saya juga ingin menyimpan gambar. Tapi masalah saya (?) Adalah saya ingin menyimpannya dari bitmap yang saya gambar.

Saya membuatnya seperti ini:

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

 }

metode simpan Anda hanya bekerja untuk saya .. setelah menghabiskan beberapa jam .. terima kasih banyak Pak.
Mohammed Sufian

5

Cara saya menemukan mengirim PNG dan transparansi.

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

Nilai 85 di sini tidak masuk akal karena PNG lossless. Dokumentasi mengatakan - `Beberapa format, seperti PNG yang lossless, akan mengabaikan pengaturan kualitas`
Minhaz

2

Buat thumbnail video untuk video. Ini dapat mengembalikan nol jika video rusak atau format tidak didukung.

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

Untuk Menyimpan bitmap Anda di sdcard gunakan kode berikut

Simpan Gambar

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

Untuk Mendapatkan Jalur Penyimpanan Gambar

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

Anda ingin menyimpan Bitmap ke Direktori Pilihan Anda. Saya telah membuat pustaka ImageWorker yang memungkinkan pengguna memuat, menyimpan, dan mengonversi gambar bitmap / drawables / base64.

Min SDK - 14

Prasyarat

  • Menyimpan file akan membutuhkan izin WRITE_EXTERNAL_STORAGE.
  • Mengambil file akan membutuhkan izin READ_EXTERNAL_STORAGE.

Menyimpan Bitmap / Drawable / Base64

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

Memuat Bitmap

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

Penerapan

Tambahkan Dependensi

Dalam Gradle Tingkat Proyek

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

Di Tingkat Aplikasi Gradle

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

Anda dapat membaca lebih lanjut di https://github.com/ihimanshurawat/ImageWorker/blob/master/README.md


1

Hei beri saja nama .bmp

Melakukan hal ini:

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

itu akan terdengar bahwa IM HANYA MENIPU DI SELURUHNYA, tetapi cobalah setelah itu akan disimpan dalam bmp foramt..Cheers


1

Pastikan direktori dibuat sebelum Anda menelepon bitmap.compress:

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

1

Setelah Android 4.4 Kitkat, dan pada tahun 2017 pangsa Android 4.4 dan kurang adalah sekitar 20% dan menurun, tidak mungkin untuk menyimpan ke kartu SD menggunakan Filekelas dan getExternalStorageDirectory()metode. Metode ini mengembalikan memori internal perangkat Anda dan gambar disimpan terlihat oleh setiap aplikasi. Anda juga dapat menyimpan gambar hanya pribadi untuk aplikasi Anda dan dihapus ketika pengguna menghapus aplikasi Anda dengan openFileOutput()metode.

Dimulai dengan Android 6.0, Anda dapat memformat kartu SD Anda sebagai memori internal tetapi hanya pribadi untuk perangkat Anda. (Jika Anda memformat mobil SD sebagai memori internal, hanya perangkat Anda yang dapat mengakses atau melihat isinya) Anda dapat menyimpan ke kartu SD itu menggunakan jawaban lain tetapi jika Anda ingin menggunakan kartu SD yang dapat dilepas Anda harus membaca jawaban saya di bawah ini.

Anda harus menggunakan Kerangka Akses Penyimpanan untuk mendapatkan onActivityResultmetode aktivitas folder ke uri untuk mendapatkan folder yang dipilih oleh pengguna, dan menambahkan izin tetap yang retreive untuk dapat mengakses folder setelah pengguna memulai ulang perangkat.

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

            }
        }
    }
}

Sekarang, simpan simpan folder ke preferensi bersama untuk tidak meminta pengguna memilih folder setiap kali Anda ingin menyimpan gambar.

Anda harus menggunakan DocumentFilekelas untuk menyimpan gambar Anda, bukan Fileatau ParcelFileDescriptor, untuk info lebih lanjut Anda dapat memeriksa utas ini untuk menyimpan gambar ke kartu SD dengan compress(CompressFormat.JPEG, 100, out);metode dan DocumentFilekelas.


1

Beberapa perangkat baru tidak menyimpan bitmap. Jadi saya jelaskan sedikit lagi ..

pastikan Anda telah menambahkan Izin di bawah ini

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

dan buat file xml di bawah xmlnama folder provider_paths.xml

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

dan di AndroidManifest di bawah

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

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

dimana

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

dan metode lainnya

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

dan

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

Apakah Anda memiliki informasi lebih lanjut tentang error handling for PIE devices..dan saya kira rekursi dalam getOutputMediaFiledapat menjadi loop tak terbatas jika penyelesaiannya gagal.
Raimund Wege

0

Simpan Bitmap ke Galeri Anda Tanpa Kompres.

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

// | == | Buat File PNG dari 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(); }
}

// | == | Dapatkan Bimap dari File:

Bitmap getBmjFrmFylFnc(String pthAndFylTtlVar)
{
    return BitmapFactory.decodeFile(pthAndFylTtlVar);
}
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.