カメラ機能を実装する際、以前の記事のように
val intent = Intent(MediaStore.ACTION_IMAGE_CAPTURE).apply { addCategory(Intent.CATEGORY_DEFAULT) } startActivityForResult(intent, CAMERA_REQUEST_CODE)
で暗黙的インテントを使用すると取得できるBitmapデータが圧縮された状態で取得され画質(解像度)が低い状態です。
なので、撮影した画像のままのBitmapを取得する方法に変更する必要があります。
FilePropider
FileProvider | Android Developers
「content://」でアクセスする時に利用するのがFileProviderです。 FileProviderでアクセスすことにより、対象フォルダの一時許可が得られます。 (ちなみにAndroid Nからファイルアクセスで「file://」が、StrictModeの設定が変わり利用できなくなりました。)
propider_paths.xml
<?xml version="1.0" encoding="utf-8"?> <paths xmlns:android="http://schemas.android.com/apk/res/android"> <external-path name="my_images" path="/" /> </paths>
カメラ/アルバム起動のパーミッション部分
AndroidManifest.xml
... <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.CAMERA" /> <activity android:name=".presentation.activities.LicenseActivity" /> <activity android:name=".presentation.activities.EditMapViewActivity"></activity> <provider android:name="android.support.v4.content.FileProvider" android:authorities="bio.enoque.enoque_android" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/provider_paths" /> </provider> </application> </manifest>
Adapter.kt(カメラ起動部)
private fun setOnclickCaptureButton(holder: MarkPostImageCaptureRecyclerViewHolder) { holder.markPostCaptureButton.setOnClickListener { val items = arrayOf("カメラ", "アルバム") AlertDialog.Builder(this.activity) .setTitle("選択してください") .setItems(items, DialogInterface.OnClickListener { dialog, which -> when (which) { // Camera 0 -> { Intent(MediaStore.ACTION_IMAGE_CAPTURE).resolveActivity(this.context.packageManager)?.let { if (this.checkPermission()) { this.takePicture() } else { this.grantCameraPermission() if (this.checkPermission()) { this.takePicture() } } } ?: Toast.makeText(this.context, "カメラを扱うアプリがありません", Toast.LENGTH_LONG).show() } 1 -> { this.selectGallery() } } }) .show() } }
Adapter.kt(パーミッション)
// permission.CAMERAとpermission.WRITE_EXTERNAL_STORAGEが許可されているかどうかを判別 private fun checkPermission(): Boolean { val cameraPermission = PackageManager.PERMISSION_GRANTED == ContextCompat.checkSelfPermission(this.context, android.Manifest.permission.CAMERA) val extraStoragePermission = PackageManager.PERMISSION_GRANTED == ContextCompat.checkSelfPermission(this.context, android.Manifest.permission.WRITE_EXTERNAL_STORAGE) return cameraPermission && extraStoragePermission } private fun grantCameraPermission() = ActivityCompat.requestPermissions(this.activity, arrayOf(android.Manifest.permission.CAMERA, android.Manifest.permission.WRITE_EXTERNAL_STORAGE), CAMERA_PERMISSION_REQUEST_CODE)
カメラ/アルバム起動部分
Adapter.kt(暗黙的インテント)
private fun takePicture() { val intent = Intent(MediaStore.ACTION_IMAGE_CAPTURE).apply { addCategory(Intent.CATEGORY_DEFAULT) putExtra(MediaStore.EXTRA_OUTPUT, createSaveFileUri()) } this.activity.startActivityForResult(intent, CAMERA_REQUEST_CODE) }
Adapter.kt(Uri生成)
private fun createSaveFileUri(): Uri { val timeStamp = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.JAPAN).format(Date()) val imageFileName = "casalack_" + timeStamp val storageDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM + "/casalack") if (!storageDir.exists()) { storageDir.mkdir() } val file = File.createTempFile( imageFileName, /* prefix */ ".jpg", /* suffix */ storageDir /* directory */ ) // this.pathはStringのグローバル変数 this.path = file.absolutePath return FileProvider.getUriForFile(this.activity, "bio.enoque.enoque_android", file) }
カメラ/アルバムの画像(bitmap)受取部分
- Activityの
onActivityResult
で受け取り、そのままAdpterに渡します - bitmapをリサイズしているのはOutOfMemory対策です
Activity.kt
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) this.adapter?.let { it.onActivityResult(requestCode, resultCode, data) } }
Adapter.kt
companion object { const val CAMERA_REQUEST_CODE = 1 const val CAMERA_PERMISSION_REQUEST_CODE = 2 const val RESULT_PICK_IMAGEFILE = 1000 } fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { if (requestCode == CAMERA_REQUEST_CODE && resultCode == Activity.RESULT_OK) { val contentValues = ContentValues().apply { put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg") put("_data", path) } this.activity.contentResolver.insert( MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues) val inputStream = FileInputStream(File(path)) val bitmap = BitmapFactory.decodeStream(inputStream) val width = bitmap.width / 7 val height = bitmap.height / 7 val resizeBitmap = Bitmap.createScaledBitmap(bitmap, width, height, true) this.markPostImageCaptureRecyclerHolder?.let { it.markPostImageView.setImageBitmap(resizeBitmap) } } else { if (resultCode != 0) { val uri = data?.getData() val inputStream = this.activity.contentResolver?.openInputStream(uri) val bitmap: Bitmap? = BitmapFactory.decodeStream(inputStream) bitmap?.let { bp -> val width = bp.width / 7 val height = bp.height / 7 val resizeBitmap = Bitmap.createScaledBitmap(bp, width, height, true) this.markPostImageCaptureRecyclerHolder?.let { it.markPostImageView.setImageBitmap(resizeBitmap) } } } } }
Kotlinスタートブック -新しいAndroidプログラミング
- 作者: 長澤太郎
- 出版社/メーカー: リックテレコム
- 発売日: 2016/07/13
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (1件) を見る
- 作者: Dmitry Jemerov,Svetlana Isakova,長澤太郎,藤原聖,山本純平,yy_yank
- 出版社/メーカー: マイナビ出版
- 発売日: 2017/10/31
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (1件) を見る