-
Cats萌萌
尝试下一个方法。如果文件夹不存在,Android Q(及更高版本)已经负责创建文件夹。该示例被硬编码为输出到DCIM文件夹中。如果您需要一个子文件夹,则将子文件夹名称附加为下一个:final String relativeLocation = Environment.DIRECTORY_DCIM + File.separator + “YourSubforderName”;考虑压缩格式应该与mime-type参数有关。例如,对于 JPEG 压缩格式,mime 类型将是“image/jpeg”,等等。可能您还想将压缩质量作为参数传递,在此示例中硬编码为 95。爪哇:@NonNullpublic Uri saveBitmap(@NonNull final Context context, @NonNull final Bitmap bitmap, @NonNull final Bitmap.CompressFormat format, @NonNull final String mimeType, @NonNull final String displayName) throws IOException { final ContentValues values = new ContentValues(); values.put(MediaStore.MediaColumns.DISPLAY_NAME, displayName); values.put(MediaStore.MediaColumns.MIME_TYPE, mimeType); values.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DCIM); final ContentResolver resolver = context.getContentResolver(); Uri uri = null; try { final Uri contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI; uri = resolver.insert(contentUri, values); if (uri == null) throw new IOException("Failed to create new MediaStore record."); try (final OutputStream stream = resolver.openOutputStream(uri)) { if (stream == null) throw new IOException("Failed to open output stream."); if (!bitmap.compress(format, 95, stream)) throw new IOException("Failed to save bitmap."); } return uri; } catch (IOException e) { if (uri != null) { // Don't leave an orphan entry in the MediaStore resolver.delete(uri, null, null); } throw e; }}科特林:@Throws(IOException::class)fun saveBitmap( context: Context, bitmap: Bitmap, format: Bitmap.CompressFormat, mimeType: String, displayName: String): Uri { val values = ContentValues().apply { put(MediaStore.MediaColumns.DISPLAY_NAME, displayName) put(MediaStore.MediaColumns.MIME_TYPE, mimeType) put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DCIM) } val resolver = context.contentResolver var uri: Uri? = null try { uri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values) ?: throw IOException("Failed to create new MediaStore record.") resolver.openOutputStream(uri)?.use { if (!bitmap.compress(format, 95, it)) throw IOException("Failed to save bitmap.") } ?: throw IOException("Failed to open output stream.") return uri } catch (e: IOException) { uri?.let { orphanUri -> // Don't leave an orphan entry in the MediaStore resolver.delete(orphanUri, null, null) } throw e }}Kotlin 变体,具有更实用的风格:@Throws(IOException::class)fun saveBitmap( context: Context, bitmap: Bitmap, format: Bitmap.CompressFormat, mimeType: String, displayName: String): Uri { val values = ContentValues().apply { put(MediaStore.MediaColumns.DISPLAY_NAME, displayName) put(MediaStore.MediaColumns.MIME_TYPE, mimeType) put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DCIM) } var uri: Uri? = null return runCatching { with(context.contentResolver) { insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values)?.also { uri = it // Keep uri reference so it can be removed on failure openOutputStream(it)?.use { stream -> if (!bitmap.compress(format, 95, stream)) throw IOException("Failed to save bitmap.") } ?: throw IOException("Failed to open output stream.") } ?: throw IOException("Failed to create new MediaStore record.") } }.getOrElse { uri?.let { orphanUri -> // Don't leave an orphan entry in the MediaStore context.contentResolver.delete(orphanUri, null, null) } throw it }}
-
慕虎7371278
private void saveImage(Bitmap bitmap, @NonNull String name) throws IOException { OutputStream fos; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { ContentResolver resolver = getContentResolver(); ContentValues contentValues = new ContentValues(); contentValues.put(MediaStore.MediaColumns.DISPLAY_NAME, name + ".jpg"); contentValues.put(MediaStore.MediaColumns.MIME_TYPE, "image/jpg"); contentValues.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_PICTURES); Uri imageUri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues); fos = resolver.openOutputStream(Objects.requireNonNull(imageUri)); } else { String imagesDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).toString(); File image = new File(imagesDir, name + ".jpg"); fos = new FileOutputStream(image); } bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos); Objects.requireNonNull(fos).close();}图像将存储在图片文件夹@根级别在直播中查看https://youtu.be/695HqaiwzQ0我创建了教程
-
浮云间
这是我经常使用的。你可以尝试一下。 private void saveImageToStorage() throws IOException { OutputStream imageOutStream; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { ContentValues values = new ContentValues(); values.put(MediaStore.Images.Media.DISPLAY_NAME, "image_screenshot.jpg"); values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg"); values.put(MediaStore.Images.Media.RELATIVE_PATH, Environment.DIRECTORY_PICTURES); Uri uri = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values); imageOutStream = getContentResolver().openOutputStream(uri); } else { String imagePath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).toString(); File image = new File(imagePath, "image_screenshotjpg"); imageOutStream = new FileOutputStream(image); } try { bitmapObject.compress(Bitmap.CompressFormat.JPEG, 100, imageOutStream); } finally { imageOutStream.close(); }}
-
守候你守候我
如果有人正在寻找如何将照片保存到 DCIM 文件夹中,以一种稍后将出现在 Google Photos 中的方式:(基于:https: //github.com/yasirkula/UnityNativeGallery/blob/670d9e2b8328f7796dd95d29dd80fadd8935b804/JAR%20Source/NativeGallery .java#L73-L96 )ContentValue values = new ContentValues();values.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DCIM);values.put(MediaStore.MediaColumns.DATE_TAKEN, System.currentTimeMillis());values.put(MediaStore.MediaColumns.IS_PENDING, true);Uri uri = context.getContentResolver().insert(externalContentUri, values);if (uri != null) { try { if (WriteFileToStream(originalFile, context.getContentResolver().openOutputStream(uri))) { values.put(MediaStore.MediaColumns.IS_PENDING, false); context.getContentResolver().update(uri, values, null, null); } } catch (Exception e) { context.getContentResolver().delete( uri, null, null ); }}WriteFileToStream从文件复制到流的标准方法在哪里。
-
慕森王
这是我的 2022 版本,此版本也在 Samsung S22 Phone 上的 Emulator SDK 27 和 30 中进行了测试。长:博士对于 SDK < 29 你需要按照这里的代码,并且在成功拍照后几乎不需要添加代码。您可以在savePictureQ(...)下面的我的功能中看到否则,如果您是 SDK >= 29,只需从函数的MediaStore.EXTRA_OUTPUTextras处传递 URIcontentResolver.insert(...)因为startActivityForResult(Intent)已经弃用了我的版本registerForActivityResult(...)private val cameraLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { if (it.resultCode == Activity.RESULT_OK) { val name: String = viewModel.savePictureQ() if (name != "") requireActivity().applicationContext.deleteFile(name) val cr = requireContext().contentResolver val uri = viewModel.getTargetUri() if (uri != null) { val bitmap = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { val source = ImageDecoder.createSource(cr, uri) ImageDecoder.decodeBitmap(source) } else MediaStore.Images.Media.getBitmap(cr, uri) val resized = Bitmap.createScaledBitmap(bitmap, 512, 512, true) } } }我在另一个名为 Repository.kt 的文件中调用 Intent,我还使用假 viewModel 来调用 Repository 代码。这是我调用 viewModel 代码的方式private lateinit var viewModel: MenuViewModeloverride fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { viewModel = MenuViewModel(Injection.provideRepository(requireContext())) ...}private fun permissionCheck() { val granted = PackageManager.PERMISSION_GRANTED val permissions = arrayOf( Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.CAMERA ) if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) { if (ActivityCompat.checkSelfPermission( requireContext(), permissions[0] ) != granted && ActivityCompat.checkSelfPermission( requireContext(), permissions[1] ) != granted && ActivityCompat.checkSelfPermission( requireContext(), permissions[2] ) != granted ) ActivityCompat.requestPermissions( requireActivity(), permissions, MainActivity.REQUEST_CODE_PERMISSION ) else MainActivity.accepted = true } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { if (ActivityCompat.checkSelfPermission( requireContext(), permissions[2] ) != granted && ActivityCompat.checkSelfPermission( requireContext(), Manifest.permission.ACCESS_MEDIA_LOCATION ) != granted ) ActivityCompat.requestPermissions( requireActivity(), arrayOf(permissions[2], Manifest.permission.ACCESS_MEDIA_LOCATION), MainActivity.REQUEST_CODE_PERMISSION ) else MainActivity.accepted = true }}override fun onViewCreated(view: View, savedInstanceState: Bundle?) { ... bind.fromCamera.setOnClickListener { permissionCheck() if (`permission granted check`) { viewModel.getCameraIntent(cameraLauncher) } } ...}在我的假 viewModel 中:class MenuViewModel(private val repository: IRepository) { fun getTargetUri() = repository.getTargetUri() fun getCameraIntent(launcher: ActivityResultLauncher<Intent>) = repository.createTakePictureIntent(launcher) fun savePictureQ(): String = repository.savePictureQ()}在我的存储库代码中:class Repository private constructor(private val context: Context) : IRepository { companion object { @Volatile private var INSTANCE: IRepository? = null fun getInstance(context: Context) = INSTANCE ?: synchronized(this) { INSTANCE ?: Repository(context).apply { INSTANCE = this } } } private var currentPath = "" private var targetUri: Uri? = null private fun createImageFile(): File { // create temporary file for SDK < 29 val timestamp = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(Date()) val storageDir = context.getExternalFilesDir(Environment.DIRECTORY_PICTURES) return File.createTempFile(timestamp, ".jpg", storageDir) .apply { currentPath = absolutePath } } override fun savePictureQ() : String { // Saving picture and added to Gallery for SDK < 29 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) { val f = File(currentPath) val cr = context.contentResolver val bitmap = BitmapFactory.decodeFile(currentPath) val path = "${Environment.DIRECTORY_PICTURES}${File.separator}PoCkDetection" val values = createContentValues(f.name, path) var uri: Uri? = null try { uri = cr.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values)!! val os = cr.openOutputStream(uri) try { val result = bitmap.compress(Bitmap.CompressFormat.JPEG, 100, os) if (!result) throw Exception() } catch (e: Exception) { e.printStackTrace() throw e } finally { os?.close() targetUri = uri } f.delete() if (f.exists()) { f.canonicalFile.delete() if (f.exists()) return f.name } } catch (e: Exception) { e.printStackTrace() uri?.let { cr.delete(it, null, null) } } } return "" } override fun getTargetUri(): Uri? = targetUri private fun createContentValues(title: String, path: String): ContentValues = ContentValues().apply { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { put(MediaStore.MediaColumns.TITLE, "$title.jpg") put(MediaStore.MediaColumns.DISPLAY_NAME, "$title.jpg") put(MediaStore.MediaColumns.MIME_TYPE, "image/jpg") put(MediaStore.MediaColumns.DATE_ADDED, System.currentTimeMillis()) put(MediaStore.MediaColumns.DATE_TAKEN, System.currentTimeMillis()) put(MediaStore.MediaColumns.RELATIVE_PATH, path) } else { put(MediaStore.Images.Media.TITLE, "$title.jpg") put(MediaStore.Images.Media.DISPLAY_NAME, "$title.jpg") put(MediaStore.Images.Media.MIME_TYPE, "image/jpg") put(MediaStore.Images.Media.DATE_ADDED, System.currentTimeMillis()) put(MediaStore.Images.Media.DATE_TAKEN, System.currentTimeMillis()) } } override fun createTakePictureIntent(launcher: ActivityResultLauncher<Intent>) { Intent(MediaStore.ACTION_IMAGE_CAPTURE).also { takePictureIntent -> takePictureIntent.resolveActivity(context.packageManager).also { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) { val photoFile: File? = try { createImageFile() } catch (e: IOException) { e.printStackTrace() null } photoFile?.also { val photoURI = FileProvider.getUriForFile(context, "com.your.package.name", it) takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI) launcher.launch(takePictureIntent) } } else { val timestamp = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(Date()) val path = "${Environment.DIRECTORY_PICTURES}${File.separator}PoCkDetection" val values = createContentValues(timestamp, path) val photoURI = context.contentResolver.insert( MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values ) targetUri = photoURI takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI) launcher.launch(takePictureIntent) } } } }}对于 SDK < 29,我遵循Google Developer的这段代码这是我的清单在遵循代码后的样子:<application ...> <provider android:name="androidx.core.content.FileProvider" android:authorities="com.your.package.name" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/camera_paths" /> </provider></application>创建名为 xml 的新 res 文件夹,然后创建新的 xml 文件,确保名称与您放置在该文件<meta-data>中<provider>和内部的名称相同:<?xml version="1.0" encoding="utf-8"?><paths> <external-files-path name="camera_take" path="Pictures" /></paths>