Skip to content

Commit 93f6829

Browse files
committed
Allow to take the photo on the fly
1 parent c398567 commit 93f6829

File tree

4 files changed

+94
-37
lines changed

4 files changed

+94
-37
lines changed

app/src/main/AndroidManifest.xml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
66
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
7+
<uses-feature android:name="android.hardware.camera" android:required="true" />
78

89
<application
910
android:allowBackup="true"
@@ -25,6 +26,16 @@
2526
<data android:mimeType="image/*" />
2627
</intent-filter>
2728
</activity>
29+
30+
<provider
31+
android:name="androidx.core.content.FileProvider"
32+
android:authorities="com.dan.perspective.provider"
33+
android:exported="false"
34+
android:grantUriPermissions="true">
35+
<meta-data
36+
android:name="android.support.FILE_PROVIDER_PATHS"
37+
android:resource="@xml/file_paths"></meta-data>
38+
</provider>
2839
</application>
2940

3041
</manifest>

app/src/main/java/com/dan/perspective/MainFragment.kt

Lines changed: 74 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,13 @@ import android.graphics.PointF
88
import android.media.MediaScannerConnection
99
import android.net.Uri
1010
import android.os.Bundle
11+
import android.os.Environment
1112
import android.os.Parcelable
13+
import android.provider.MediaStore
1214
import android.util.Log
1315
import android.view.*
1416
import androidx.appcompat.app.AppCompatActivity
17+
import androidx.core.content.FileProvider
1518
import androidx.documentfile.provider.DocumentFile
1619
import com.dan.perspective.databinding.MainFragmentBinding
1720
import org.opencv.android.Utils
@@ -21,6 +24,8 @@ import org.opencv.core.Rect
2124
import org.opencv.core.Size
2225
import org.opencv.imgproc.Imgproc.*
2326
import java.io.File
27+
import java.text.SimpleDateFormat
28+
import java.util.*
2429
import kotlin.math.PI
2530
import kotlin.math.abs
2631
import kotlin.math.max
@@ -29,12 +34,12 @@ import kotlin.math.min
2934

3035
class MainFragment(activity: MainActivity) : AppFragment(activity) {
3136
companion object {
32-
const val MSG_LOAD = "Loading"
3337
const val MSG_AUTO_DETECT = "Auto detect"
3438
const val MSG_WARP = "Warping"
3539
const val MSG_SAVE = "Saving"
3640

3741
const val INTENT_OPEN_IMAGE = 2
42+
const val INTENT_TAKE_PHOTO = 3
3843

3944
const val AUTO_DETECT_WORK_SIZE = 1024
4045

@@ -49,6 +54,7 @@ class MainFragment(activity: MainActivity) : AppFragment(activity) {
4954
private var menuSave: MenuItem? = null
5055
private var menuPrevPerspective: MenuItem? = null
5156
private val sharedParams = SharedParams()
57+
private lateinit var tmpPhotoFile: File
5258

5359
private lateinit var binding: MainFragmentBinding //: ActivityMainBinding by lazy { ActivityMainBinding.inflate(layoutInflater) }
5460
private var outputName = Settings.DEFAULT_NAME
@@ -85,6 +91,11 @@ class MainFragment(activity: MainActivity) : AppFragment(activity) {
8591
return true
8692
}
8793

94+
R.id.takePhoto -> {
95+
startActivityToTakePhoto()
96+
return true
97+
}
98+
8899
R.id.save -> {
89100
saveImage()
90101
return true
@@ -127,8 +138,20 @@ class MainFragment(activity: MainActivity) : AppFragment(activity) {
127138
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
128139
super.onActivityResult(requestCode, resultCode, data)
129140

130-
if (resultCode == AppCompatActivity.RESULT_OK && requestCode == INTENT_OPEN_IMAGE) {
131-
data?.data?.let { uri -> setImage(uri) }
141+
if (resultCode == AppCompatActivity.RESULT_OK && null != data) {
142+
when (requestCode) {
143+
INTENT_OPEN_IMAGE -> {
144+
data.data?.let { uri -> setImage(uri) }
145+
}
146+
147+
INTENT_TAKE_PHOTO -> {
148+
if (tmpPhotoFile.exists()) {
149+
val name = SimpleDateFormat("yyyyMMdd_HHmmss_SSS", Locale.US).format(Date(System.currentTimeMillis()))
150+
setImage( Uri.fromFile(tmpPhotoFile), name )
151+
tmpPhotoFile.delete()
152+
}
153+
}
154+
}
132155
}
133156
}
134157

@@ -143,6 +166,18 @@ class MainFragment(activity: MainActivity) : AppFragment(activity) {
143166
startActivityForResult(intent, INTENT_OPEN_IMAGE)
144167
}
145168

169+
private fun startActivityToTakePhoto() {
170+
val tmpUri = FileProvider.getUriForFile(
171+
requireContext(),
172+
"com.dan.perspective.provider",
173+
tmpPhotoFile)
174+
175+
val intent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
176+
.putExtra(MediaStore.EXTRA_OUTPUT, tmpUri)
177+
178+
startActivityForResult(intent, INTENT_TAKE_PHOTO)
179+
}
180+
146181
private fun matToBitmap(image: Mat): Bitmap? {
147182
if (image.empty()) return null
148183

@@ -156,41 +191,41 @@ class MainFragment(activity: MainActivity) : AppFragment(activity) {
156191
return bitmap
157192
}
158193

159-
private fun setImage(uri: Uri) {
160-
runAsync(MSG_LOAD) {
161-
inputImage = loadImage(uri)
162-
val bitmap = matToBitmap(inputImage)
163-
164-
runOnUiThread {
165-
binding.imageEdit.setBitmap(bitmap)
194+
private fun setImage(uri: Uri, suggestedName: String? = null) {
195+
val matAndBitmap = loadImage(uri)
196+
if (null == matAndBitmap) {
197+
showToast("Failed to load the image")
198+
return
199+
}
166200

167-
if (null == bitmap) {
168-
showToast("Failed to load the image")
169-
} else {
170-
outputName = Settings.DEFAULT_NAME
171-
172-
try {
173-
DocumentFile.fromSingleUri(
174-
requireContext(),
175-
uri
176-
)?.name?.let { name ->
177-
if (name.isNotEmpty()) {
178-
val fields = name.split('.')
179-
outputName = fields[0]
180-
}
181-
}
182-
} catch (e: Exception) {
183-
e.printStackTrace()
201+
inputImage = matAndBitmap.first
202+
binding.imageEdit.setBitmap(matAndBitmap.second)
203+
204+
if (null != suggestedName) {
205+
outputName = suggestedName
206+
} else {
207+
outputName = Settings.DEFAULT_NAME
208+
209+
try {
210+
DocumentFile.fromSingleUri(
211+
requireContext(),
212+
uri
213+
)?.name?.let { name ->
214+
if (name.isNotEmpty()) {
215+
val fields = name.split('.')
216+
outputName = fields[0]
184217
}
185218
}
219+
} catch (e: Exception) {
220+
e.printStackTrace()
221+
}
222+
}
186223

187-
clearOutputImage()
188-
updateButtons()
224+
clearOutputImage()
225+
updateButtons()
189226

190-
if (settings.autoDetectOnOpen) {
191-
autoDetectPerspective()
192-
}
193-
}
227+
if (settings.autoDetectOnOpen) {
228+
autoDetectPerspective()
194229
}
195230
}
196231

@@ -208,19 +243,19 @@ class MainFragment(activity: MainActivity) : AppFragment(activity) {
208243
menuPrevPerspective?.isEnabled = enabled && settings.prevHeight > 0
209244
}
210245

211-
private fun loadImage(uri: Uri) : Mat {
246+
private fun loadImage(uri: Uri) : Pair<Mat,Bitmap>? {
212247
try {
213-
val inputStream = requireContext().contentResolver.openInputStream(uri) ?: return Mat()
248+
val inputStream = requireContext().contentResolver.openInputStream(uri) ?: return null
214249
val bitmap = BitmapFactory.decodeStream(inputStream)
215250
val image = Mat()
216251
Utils.bitmapToMat(bitmap, image)
217252
inputStream.close()
218-
return image
253+
return Pair(image, bitmap)
219254
} catch (e: Exception) {
220255
e.printStackTrace()
221256
}
222257

223-
return Mat()
258+
return null
224259
}
225260

226261
private fun saveImageAsync() {
@@ -539,6 +574,8 @@ class MainFragment(activity: MainActivity) : AppFragment(activity) {
539574
container: ViewGroup?,
540575
savedInstanceState: Bundle?
541576
): View {
577+
tmpPhotoFile = File(requireContext().getExternalFilesDir(Environment.DIRECTORY_PICTURES), "tmp.jpg")
578+
542579
binding = MainFragmentBinding.inflate(inflater)
543580

544581
updateButtons()

app/src/main/res/menu/main_menu.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@
77
android:icon="@android:drawable/ic_menu_gallery"
88
android:title="Open"
99
app:showAsAction="always" />
10+
<item
11+
android:id="@+id/takePhoto"
12+
android:icon="@android:drawable/ic_menu_camera"
13+
android:title="Take photo"
14+
app:showAsAction="always" />
1015
<item
1116
android:id="@+id/save"
1217
android:icon="@android:drawable/ic_menu_save"
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<paths xmlns:android="http://schemas.android.com/apk/res/android">
3+
<external-files-path name="tmp" path="Pictures" />
4+
</paths>

0 commit comments

Comments
 (0)