我正在研究从web服务器下载图像的功能,在屏幕上显示它,如果用户希望保持图像,将其保存在SD卡的某个文件夹中。有没有一种简单的方法来获取位图并将其保存到我选择的SD卡文件夹中?
我的问题是,我可以下载图像,在屏幕上显示为位图。我能够找到的将图像保存到特定文件夹的唯一方法是使用FileOutputStream,但这需要一个字节数组。我不知道如何转换(如果这是正确的方式)从位图到字节数组,所以我可以使用FileOutputStream写入数据。
我的另一个选择是使用MediaStore:
MediaStore.Images.Media.insertImage(getContentResolver(), bm,
barcodeNumber + ".jpg Card Image", barcodeNumber + ".jpg Card Image");
它可以很好地保存到SD卡,但不允许您自定义文件夹。
我还想保存一张图片。但是我的问题(?)是我想从我画的位图中保存它。
我是这样写的:
@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();
}
}
我知道这个问题很老了,但是现在我们可以在没有WRITE_EXTERNAL_STORAGE权限的情况下实现相同的结果。而不是我们可以使用文件提供程序。
private fun storeBitmap(bitmap: Bitmap, file: File){
requireContext().getUriForFile(file)?.run {
requireContext().contentResolver.openOutputStream(this)?.run {
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, this)
close()
}
}
}
如何从提供者检索文件?
fun Context.getUriForFile(file: File): Uri? {
return FileProvider.getUriForFile(
this,
"$packageName.fileprovider",
file
)
}
另外,不要忘记在Android manifest中注册你的提供商
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths"/>
</provider>
您应该使用Bitmap.compress()方法将位图保存为文件。它将压缩(如果所使用的格式允许的话)您的图片并将其推入OutputStream。
下面是一个通过getImageBitmap(myurl)获得的位图实例,可以压缩为JPEG,压缩率为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());
在Android 4.4 Kitkat之后,截至2017年,Android 4.4及以下的份额约为20%并且正在下降,使用File类和getExternalStorageDirectory()方法保存到SD卡是不可能的。这个方法返回你的设备内部内存和图像保存为每个应用程序可见。你也可以只保存你的应用程序私有的图像,当用户使用openFileOutput()方法删除你的应用程序时删除。
从Android 6.0开始,您可以将SD卡格式化为内部内存,但只能对您的设备私有。(如果你格式化SD车作为内部存储器,只有你的设备可以访问或看到它的内容)你可以使用其他答案保存到SD卡,但如果你想使用一个可移动的SD卡,你应该阅读下面我的回答。
您应该使用存储访问框架获取uri到activity的onActivityResult方法来获取用户选择的文件夹,并添加检索持久权限,以便用户重新启动设备后能够访问文件夹。
@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);
}
}
}
}
现在,保存保存文件夹到共享首选项,而不是每次你想保存图像时都要求用户选择文件夹。
你应该使用DocumentFile类来保存你的图像,而不是File或ParcelFileDescriptor,要了解更多信息,你可以检查这个线程保存图像到SD卡压缩(CompressFormat.JPEG, 100, out);方法和DocumentFile类。