保存位图到位置

我正在研究从web服务器下载图像的功能,在屏幕上显示它,如果用户希望保持图像,将其保存在SD卡的某个文件夹中。有没有一种简单的方法来获取位图并将其保存到我选择的SD卡文件夹中?

我的问题是,我可以下载图像,在屏幕上显示为位图。我能够找到的将图像保存到特定文件夹的唯一方法是使用FileOutputStream,但这需要一个字节数组。我不知道如何转换(如果这是正确的方式)从位图到字节数组,所以我可以使用FileOutputStream写入数据。

我的另一个选择是使用MediaStore:

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

它可以很好地保存到SD卡,但不允许您自定义文件夹。

560019 次浏览

为什么不使用100调用Bitmap.compress方法(这听起来像是无损的)?

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

有些格式,比如无损的PNG,会忽略质量设置。

你应该使用Bitmap.compress()方法将位图保存为文件。它将压缩(如果所使用的格式允许的话)您的图片并将其推入OutputStream。

下面是一个通过getImageBitmap(myurl)获得的位图实例,它可以压缩为压缩率为85%的JPEG:

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

我还想保存一张图片。但是我的问题(?)是我想从我画的位图中保存它。

我是这样写的:

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


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


}
outStream = new FileOutputStream(file);

将在AndroidManifest.xml中抛出异常(至少在os2.2中):

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

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

嘿,把名字给bmp格式

这样做:

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

这将听起来,IM只是愚弄周围,但尝试一下,它会被保存在bmp的foramt..干杯

我发现发送PNG和透明度的方式。

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

确保在调用bitmap.compress之前创建了目录:

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

下面是保存位图到文件的示例代码:

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

现在调用这个函数将位图保存到内部内存中。

File newfile = savebitmap(bitmap);

我希望它能对你有所帮助。 快乐编码生活。< / p >

// |==|从位图创建PNG文件:

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

从文件中获取Bimap:

Bitmap getBmjFrmFylFnc(String pthAndFylTtlVar)
{
return BitmapFactory.decodeFile(pthAndFylTtlVar);
}

在Android 4.4 Kitkat之后,截至2017年,Android 4.4及以下的份额约为20%并且正在下降,使用File类和getExternalStorageDirectory()方法保存到SD卡是不可能的。这个方法返回你的设备内部内存和图像保存为每个应用程序可见。你也可以只保存你的应用程序私有的图像,当用户使用openFileOutput()方法删除你的应用程序时删除。

从Android 6.0开始,您可以将SD卡格式化为内部内存,但只能对您的设备私有。(如果你格式化SD车作为内部存储器,只有你的设备可以访问或看到它的内容)你可以使用其他答案保存到SD卡,但如果你想使用一个可移动的SD卡,你应该阅读下面我的回答。

你应该使用存储访问框架获取uri到文件夹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类来保存你的图像,而不是FileParcelFileDescriptor,要了解更多信息,你可以检查这个线程将图像保存到SD卡,使用compress(CompressFormat.JPEG, 100, out);方法和DocumentFile类。

为视频创建一个视频缩略图。如果视频损坏或格式不支持,它可能返回null。

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

使用以下代码将位图保存在sdcard中

商店形象

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

获取图像存储路径

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

您想要保存位图到您选择的目录。我做了一个ImageWorker库,使用户能够加载,保存和转换位图/绘图/base64图像。

最小SDK - 14

先决条件

  • 保存文件需要WRITE_EXTERNAL_STORAGE权限。
  • 检索文件需要READ_EXTERNAL_STORAGE权限。

保存位图/可拉的Base64

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

加载位图

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

实现

添加依赖关系

在项目级别Gradle

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

在应用级Gradle

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

你可以在https://github.com/ihimanshurawat/ImageWorker/blob/master/README.md上阅读更多

一些新设备不保存位图,所以我解释了一点。

确保你已经添加了下面的权限

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

并在xml文件夹名为provider_paths.xml下创建一个xml文件

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

和在AndroidManifest下

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

然后简单地调用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());
}
}

以及其他方法

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

而且

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

保存位图到您的图库没有压缩。

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

我知道这个问题很老了,但现在我们可以在没有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

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