Bitmap'i konuma kaydet


469

Bir web sunucusundan görüntü indirmek, ekranda görüntülemek için bir işlev üzerinde çalışıyorum ve kullanıcı görüntüyü tutmak istiyorsa, belirli bir klasördeki SD karta kaydedin. Bir bitmap almanın ve seçtiğim bir klasörde SD karta kaydetmenin kolay bir yolu var mı?

Benim sorunum, görüntüyü indirebilir, ekranda bir Bitmap olarak görüntüleyebilirim. Bir görüntüyü belirli bir klasöre kaydetmenin tek yolu FileOutputStream kullanmaktır, ancak bu bir bayt dizisi gerektirir. Bitmap bayt dizisine (bu bile doğru yol ise) dönüştürmek nasıl emin değilim, bu yüzden veri yazmak için bir FileOutputStream kullanabilirsiniz.

Sahip olduğum diğer seçenek MediaStore'u kullanmaktır:

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

SD karta kaydetmek için iyi çalışır, ancak klasörü özelleştirmenize izin vermez.


Tam olarak benim app ne yapıyorum. Bunu işlemek ve üzeri bir imageView doğrudan bit eşlem yüklemek web sunucusu Büyük bir resim formunu indirmek mImage.setImageBitmap(_result.getBitmap());benim de onTaskComplete()callback'inde. Artık kullanıcıların uzun basın bağlam menüsü aracılığıyla dosyayı yerel olarak kaydetmelerine izin vermem gerekiyor. Aşağıdaki çözümü kullanabilmeliyim. Ne bilmek istiyorum, buna daha iyi bir yaklaşım buldunuz mu?
wired00

Burada yapmanın zarif bir yolu var: stackoverflow.com/questions/4263375/…
Chepech

Yanıtlar:


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
Görüntüyü de sıkıştırdım ama yüzde 100'e kadar ve görüntümü tuvalde aldığımda çok küçük. herhangi bir nedenle?
AZ_

3
@Aizaz Bu, görüntünün boyutunu değiştirmez, yalnızca biçimini ve (potansiyel olarak) kalitesini değiştirir. Ayrıca, 90yukarıdaki örnekte sıkıştırma kalitesinin PNG olarak kaydederken herhangi bir etkisi olmayacağını, ancak JPEG'ler için bir fark yaratacağını belirtmek gerekir. Bir JPEG durumunda, 0 ile 100 arasında herhangi bir sayı seçebilirsiniz.
plowman

1
Bu şekilde .JPEG için% 100 kalite ile kaydedilmesinin aslında web'deki orijinalden farklı bir görüntü kaydedeceği unutulmamalıdır (en azından daha fazla yer kaplayacaktır), Alternatif yaklaşımı düşünün.
Warpzit

42
Biri mu var tekrar sıkıştırmak? Sadece orijinal görüntüyü kaydetmek istiyorum.
Hein du Plessis

2
@HeinduPlessis Gerek yok ama muhtemelen yapmalısın. Ham bitmap'in kaydedilmesi formata bağlı olarak çok daha fazla yer kaplar (örneğin ARGB_4444 ve ARGB_8888).
irwinb

134

Bitmap.compress()Bir Bitmap'i dosya olarak kaydetmek için yöntemi kullanmalısınız . Resminizi sıkıştırır (kullanılan biçim izin veriyorsa) ve bir OutputStream içine iter.

Burada elde edilen ve getImageBitmap(myurl)% 85 sıkıştırma oranına sahip bir JPEG olarak sıkıştırılabilen bir Bitmap örneği örneği :

// 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 bunun için herhangi bir sebep fOut.flush()atlamak mümkün değil mi?
Niklas

@Niklas Bence sifonu atlayabilirsin.
JoaquinG

1
Daha az belirsizlik için ifadeyi "% 85 sıkıştırma oranı" ndan "% 85 kalite oranı" na değiştirmelisiniz. "% 85 sıkıştırma oranı" nı "% 15 kalite" olarak yorumlayacağım, ancak int parametresi Bitmap.compresskaliteyi belirtir.
Tim Cooke

yöntemi plz gönderebilir getImageBitmap(myurl)
miyim

38
outStream = new FileOutputStream(file);

AndroidManifest.xml dosyasında izinsiz olarak istisna atar (en azından os2.2'de):

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

10
AbsolutePath dosyanız dahili bir yol değilse değil mi?
Blundell

24

İçinde 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
buna "pippo.jpg" diyorsunuz ama PNG sıkıştırmasını kullanıyorsunuz
Ralphleon

1
bitmap kalitesini değiştirmek istiyorsanız sıkıştırma formatı .JPEG olmalıdır. Kalite, PNG biçiminde değiştirilemez.
Mustafa Güven

13

PNG gibi kayıpsız olan bazı formatlar kalite ayarını yok sayar.


2
PNG hala sıkıştırılmış bir biçimdir. Kalite ayarı sıkıştırma kalitesini değiştirmiyor mu?
Tamás Barta

Dokümanlar durumu (benim tarafımdan vurgulanıyor): Kompresöre ipucu, 0-100. 0 küçük boyutlu sıkıştırma, 100 maksimum kaliteli sıkıştırma anlamına gelir. PNG gibi kayıpsız olan bazı formatlar kalite ayarını göz ardı edecektir
Stephan Henningsen

10

Bitmap'i dosyaya kaydetmek için örnek kod:

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

Şimdi bitmap'i dahili belleğe kaydetmek için bu işlevi çağırın.

File newfile = savebitmap(bitmap);

Umarım bu sana yardımcı olur. Mutlu kodlama hayatı.


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
bunu 'sıkıştır' yönteminde geçiriyorsanız dışarı akışını temizlemeniz gerekmez. bu yöntem sizin adınıza yapılacaktır.
dharam

7

Neden Bitmap.compressyöntemi 100 ile çağırmıyorsunuz (kulağa kayıpsız gibi geliyor)?


Göz ardı edilmesine rağmen 100 olmalıdır. Bir gün sıkıştırma formatı gevşek bir şekilde değiştirilirse, görüntü gevşek olarak en yakın şekilde eşleşecektir. Ayrıca, bu çağrıyı özetleyen bir kodunuz varsa, bunun daha önemli olabileceğini unutmayın.
ddcruver

2
JPEG, FWIW ile% 100 kayıpsız değildir. Bitmap'i tekrar tekrar yükleyip kaydederek bunu doğrulayabilirsiniz.

5

Ayrıca bir resim kaydetmek istiyorum. Ama benim sorunum (?) Çizdiğim bir bitmapten kurtarmak istiyorum.

Ben böyle yaptım:

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

 }

tasarruf yönteminiz sadece benim için çalışıyor .. birkaç saat harcadıktan sonra .. çok teşekkürler efendim.
Muhammed Sufyan

5

PNG ve şeffaflık gönderme yöntemim.

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

PNG'nin kayıpsız olması nedeniyle buradaki 85 değeri anlamsızdır. Dokümantasyon diyor ki - `` PNG gibi kayıpsız olan bazı formatlar kalite ayarını göz ardı edecek``
Minhaz

2

Bir video için video küçük resmi oluşturun. Video bozuksa veya biçim desteklenmiyorsa null değeri döndürebilir.

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

Bitmap'inizi sdcard'a kaydetmek için aşağıdaki kodu kullanın

Mağaza Resmi

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

Görüntü Depolama Yolunu Bulmak İçin

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

Bitmap'i Seçtiğiniz Dizine kaydetmek istiyorsunuz. Kullanıcının bitmap'leri / çekilebilirleri / base64 görüntüleri yüklemesini, kaydetmesini ve dönüştürmesini sağlayan bir kütüphane ImageWorker yaptım.

Min. SDK - 14

Önkoşul

  • Dosyaların kaydedilmesi WRITE_EXTERNAL_STORAGE izni gerektirir.
  • Dosyaları almak için READ_EXTERNAL_STORAGE izni gerekir.

Bitmap / Çekilebilir / Base64 Kaydetme

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

Bitmap yükleniyor

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

uygulama

Bağımlılıklar Ekleyin

Proje Seviyesinde

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

Uygulama Seviyesinde

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

Https://github.com/ihimanshurawat/ImageWorker/blob/master/README.md adresinde daha fazla bilgi bulabilirsiniz.


1

Hey sadece .bmp'ye isim verin

Bunu yap:

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

Bu SADECE ÇEVRESİNDE ŞİMDİYE KADAR ses geliyor ama bmp foramt kaydedilecektir kez deneyin ..


1

Aramadan önce dizinin oluşturulduğundan emin olun bitmap.compress:

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

1

Android 4.4 Kitkat'tan sonra ve 2017 itibariyle Android 4.4 ve daha düşük olanların payı yaklaşık% 20 ve azalıyor, Filesınıf ve getExternalStorageDirectory()yöntem kullanarak SD karta kaydetmek mümkün değil . Bu yöntem, cihazınızın dahili belleğini döndürür ve görüntüler her uygulama tarafından görülebilir. Ayrıca görüntüleri yalnızca uygulamanıza özel olarak kaydedebilir ve kullanıcı uygulamanızı openFileOutput()yöntemle sildiğinde silinir .

Android 6.0 ile başlayarak, SD kartınızı dahili bir bellek olarak biçimlendirebilirsiniz, ancak yalnızca cihazınıza özel olarak biçimlendirebilirsiniz. (SD arabayı dahili bellek olarak biçimlendirirseniz, yalnızca cihazınız içeriğine erişebilir veya içeriğini görebilir) Bu SD karta kaydedebilirsiniz diğer cevaplar, ancak çıkarılabilir bir SD kart kullanmak istiyorsanız aşağıdaki cevabımı okumalısınız.

Klasör kullanıcı tarafından seçilen klasörü almak için klasör yöntemine uri almak için Depolama Erişimi Çerçevesi'ni kullanmalı onActivityResultve kullanıcı aygıtı yeniden başlattıktan sonra klasöre erişebilmek için kalıcı izin izni eklemelisiniz.

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

            }
        }
    }
}

Şimdi, her görüntü kaydetmek istediğinizde kullanıcıdan klasör seçmesini istememek için kaydetme klasörünü paylaşılan tercihlere kaydedin.

Sen kullanmalıdır DocumentFilegörüntünüzü değil, kurtarmak için sınıf Fileveya ParcelFileDescriptorkontrol edebilirsiniz daha fazla bilgi için, bu konu ile SD karta görüntü kaydetmek için compress(CompressFormat.JPEG, 100, out);yöntem ve DocumentFilesınıflar.


1

Bazı yeni cihazlar bitmap'i kaydetmiyor, bu yüzden biraz daha açıkladım ..

aşağıya izin eklediğinizden emin olun

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

ve altında xml dosyası oluşturmak xmlklasör adı provider_paths.xml

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

ve Android'de

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

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

nerede

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

ve diğer yöntemler

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

ve

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

Hakkında daha fazla bilginiz var mı ve geçici çözüm başarısız olursa error handling for PIE devices..yineleme getOutputMediaFilesonsuz bir döngü olabilir sanırım .
Raimund Wege

0

Bitmap'i Sıkıştırmadan Galerinize kaydedin.

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

// | == | Bitmap'den bir PNG Dosyası oluşturun:

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

// | == | Dosyadan Bimap Alın:

Bitmap getBmjFrmFylFnc(String pthAndFylTtlVar)
{
    return BitmapFactory.decodeFile(pthAndFylTtlVar);
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.