Zuletzt aktiv 1751943995

capitalex's Avatar capitalex hat die Gist bearbeitet 1751943995. Zu Änderung gehen

1 file changed, 245 insertions

MainActivity.kt(Datei erstellt)

@@ -0,0 +1,245 @@
1 + package com.ogletree.composecameraexample
2 +
3 + import android.content.ContentResolver
4 + import android.content.ContentValues
5 + import android.graphics.Bitmap
6 + import android.graphics.BitmapFactory
7 + import android.graphics.Matrix
8 + import android.net.Uri
9 + import android.os.Bundle
10 + import android.provider.MediaStore
11 + import androidx.activity.ComponentActivity
12 + import androidx.activity.compose.setContent
13 + import androidx.activity.result.ActivityResultLauncher
14 + import androidx.activity.result.contract.ActivityResultContracts
15 + import androidx.compose.foundation.Image
16 + import androidx.compose.foundation.background
17 + import androidx.compose.foundation.clickable
18 + import androidx.compose.foundation.layout.*
19 + import androidx.compose.material.MaterialTheme
20 + import androidx.compose.material.OutlinedButton
21 + import androidx.compose.material.Surface
22 + import androidx.compose.material.Text
23 + import androidx.compose.runtime.*
24 + import androidx.compose.ui.Alignment
25 + import androidx.compose.ui.Modifier
26 + import androidx.compose.ui.graphics.ImageBitmap
27 + import androidx.compose.ui.graphics.asImageBitmap
28 + import androidx.compose.ui.text.font.FontWeight
29 + import androidx.compose.ui.tooling.preview.Preview
30 + import androidx.compose.ui.unit.dp
31 + import com.ogletree.composecameraexample.ui.theme.ComposeCameraExampleTheme
32 + import java.text.SimpleDateFormat
33 + import java.util.*
34 + import kotlin.math.min
35 +
36 +
37 + class MainActivity : ComponentActivity() {
38 + enum class CameraPermissionStatus { NoPermission, PermissionGranted, PermissionDenied }
39 +
40 + override fun onCreate(savedInstanceState: Bundle?) {
41 + super.onCreate(savedInstanceState)
42 +
43 + val cameraPermissionStatusState = mutableStateOf(CameraPermissionStatus.NoPermission)
44 + val photoUriState: MutableState<Uri?> = mutableStateOf(null)
45 + val hasPhotoState = mutableStateOf(value = false)
46 + val resolver = applicationContext.contentResolver
47 +
48 + val requestPermissionLauncher =
49 + registerForActivityResult(ActivityResultContracts.RequestPermission()){ isGranted: Boolean ->
50 + if (isGranted) {
51 + cameraPermissionStatusState.value = CameraPermissionStatus.PermissionGranted
52 + } else {
53 + cameraPermissionStatusState.value = CameraPermissionStatus.PermissionDenied
54 + }
55 + }
56 +
57 + val takePhotoLauncher =
58 + registerForActivityResult(ActivityResultContracts.TakePicture()) { isSaved ->
59 + hasPhotoState.value = isSaved
60 + }
61 +
62 + val takePhoto: () -> Unit = {
63 + hasPhotoState.value = false
64 +
65 + val values = ContentValues().apply {
66 + val title = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.US).format(Date())
67 + put(MediaStore.Images.Media.TITLE, "Compose Camera Example Image - $title")
68 + put(MediaStore.Images.Media.DISPLAY_NAME, title)
69 + put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg")
70 + put(MediaStore.Images.Media.DATE_TAKEN, System.currentTimeMillis())
71 + }
72 +
73 + val uri = resolver.insert(
74 + MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
75 + values
76 + )
77 + takePhotoLauncher.launch(uri)
78 + photoUriState.value = uri
79 +
80 + }
81 +
82 + // Ideally these would be cached instead of reloaded
83 + val getThumbnail: (Uri?) -> ImageBitmap? = { uri ->
84 + val targetSize = 256f
85 + println("URI is $uri")
86 + uri?.let {
87 + println("Opening Input Stream")
88 + resolver.openInputStream(it)
89 + }?.let {
90 + BitmapFactory.decodeStream(it)
91 + }?.let {
92 + val height = it.height.toFloat()
93 + val width = it.width.toFloat()
94 + val scaleFactor = min(targetSize / height, targetSize / width)
95 + Bitmap.createScaledBitmap(it, (scaleFactor * width).toInt() , (scaleFactor * height).toInt(), true)
96 + }?.let {
97 + val rotation = getImageRotation(resolver, uri)
98 + Bitmap.createBitmap(it, 0, 0, it.width, it.height, Matrix().apply { postRotate(rotation.toFloat()) }, true)
99 + }?.asImageBitmap()
100 +
101 + }
102 +
103 + val getFullImage: (Uri?) -> ImageBitmap? = { uri ->
104 + uri?.let {
105 + resolver.openInputStream(it)
106 + }?.let {
107 + BitmapFactory.decodeStream(it)
108 + }?.let {
109 + val rotation = getImageRotation(resolver, uri)
110 + Bitmap.createBitmap(it, 0, 0, it.width, it.height, Matrix().apply { postRotate(rotation.toFloat()) }, true)
111 + }?.asImageBitmap()
112 +
113 + }
114 +
115 + setContent {
116 + val cameraPermissionStatus by remember { cameraPermissionStatusState }
117 + val hasPhoto by remember { hasPhotoState }
118 + var shouldShowFullImage by remember { mutableStateOf(false) }
119 + ComposeCameraExampleTheme {
120 + Box(modifier = Modifier.fillMaxSize()) {
121 + Column(
122 + modifier = Modifier.fillMaxSize(),
123 + verticalArrangement = Arrangement.Center,
124 + horizontalAlignment = Alignment.CenterHorizontally
125 + ) {
126 + TakePhotoButton(
127 + cameraPermissionStatus = cameraPermissionStatus,
128 + requestPermissionLauncher = requestPermissionLauncher,
129 + takePhoto = takePhoto
130 + )
131 + if (hasPhoto) {
132 + val bitmap = getThumbnail(photoUriState.value)
133 + println("Is bitmap null: $bitmap")
134 + if (bitmap != null) {
135 + Image(
136 + bitmap = bitmap,
137 + contentDescription = "Thumbnail of Save Photo",
138 + modifier = Modifier.clickable {
139 + shouldShowFullImage = true
140 + }
141 + )
142 + }
143 + }
144 + }
145 +
146 + if (shouldShowFullImage && hasPhoto) {
147 + val bitmap =getFullImage(photoUriState.value)
148 + if (bitmap != null){
149 + Box(modifier = Modifier.fillMaxSize().clickable {
150 + shouldShowFullImage = false
151 + }){
152 + Image(
153 + bitmap = bitmap,
154 + contentDescription = "Full image of Save Photo",
155 + modifier = Modifier.align(Alignment.Center)
156 + )
157 + Surface(
158 + modifier = Modifier
159 + .background(MaterialTheme.colors.background)
160 + .align(Alignment.Center)
161 + .padding(8.dp)
162 + ) {
163 + Text(
164 + text = "Click to Close",
165 + style = MaterialTheme.typography.h4.copy(
166 + fontWeight = FontWeight.ExtraBold
167 + )
168 + )
169 + }
170 + }
171 +
172 +
173 + } else {
174 + shouldShowFullImage = false
175 + }
176 +
177 + }
178 + }
179 + }
180 + }
181 + }
182 +
183 + private fun getImageRotation(resolver: ContentResolver, uri: Uri): Int {
184 + val cursor = resolver.query(uri, arrayOf(MediaStore.Images.Media.ORIENTATION), null, null, null)
185 + var result = 0
186 +
187 + cursor?.apply {
188 + moveToFirst()
189 + val index = getColumnIndex(MediaStore.Images.Media.ORIENTATION)
190 + result = getInt(index)
191 + close()
192 + }
193 + println("Rotation = $result")
194 + return result
195 + }
196 +
197 + }
198 +
199 + @Composable
200 + fun TakePhotoButton(
201 + cameraPermissionStatus: MainActivity.CameraPermissionStatus,
202 + requestPermissionLauncher: ActivityResultLauncher<String>,
203 + takePhoto: () -> Unit
204 + ) {
205 + OutlinedButton(
206 + onClick = {
207 + when (cameraPermissionStatus) {
208 + MainActivity.CameraPermissionStatus.NoPermission ->
209 + requestPermissionLauncher.launch(android.Manifest.permission.CAMERA)
210 +
211 + MainActivity.CameraPermissionStatus.PermissionGranted ->
212 + takePhoto()
213 +
214 +
215 + MainActivity.CameraPermissionStatus.PermissionDenied -> {}
216 +
217 + }
218 + }
219 + ) {
220 + when (cameraPermissionStatus) {
221 + MainActivity.CameraPermissionStatus.NoPermission ->
222 + Text(text = "Request Camera Permissions")
223 +
224 + MainActivity.CameraPermissionStatus.PermissionDenied ->
225 + Text(text = "Camera Permissions Have Been Denied")
226 +
227 + MainActivity.CameraPermissionStatus.PermissionGranted ->
228 + Text(text = "Take Photo")
229 + }
230 + }
231 + }
232 +
233 +
234 + @Composable
235 + fun Greeting(name: String) {
236 + Text(text = "Hello $name!")
237 + }
238 +
239 + @Preview(showBackground = true)
240 + @Composable
241 + fun DefaultPreview() {
242 + ComposeCameraExampleTheme {
243 + Greeting("Android")
244 + }
245 + }
Neuer Älter