Skip to content

Commit 7de72ae

Browse files
author
Dan Oprea
committed
Fix bug: warp before saving if needed
1 parent 7f5bad2 commit 7de72ae

File tree

1 file changed

+126
-97
lines changed

1 file changed

+126
-97
lines changed

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

Lines changed: 126 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,11 @@ class MainActivity : AppCompatActivity() {
5050
Manifest.permission.WRITE_EXTERNAL_STORAGE
5151
)
5252

53+
const val MSG_LOAD = "Loading"
54+
const val MSG_AUTO_DETECT = "Auto detect"
55+
const val MSG_WARP = "Warping"
56+
const val MSG_SAVE = "Saving"
57+
5358
const val REQUEST_PERMISSIONS = 1
5459
const val INTENT_OPEN_IMAGE = 2
5560

@@ -203,7 +208,6 @@ class MainActivity : AppCompatActivity() {
203208
}
204209

205210
R.id.save -> {
206-
warpImage()
207211
saveImage()
208212
return true
209213
}
@@ -346,7 +350,7 @@ class MainActivity : AppCompatActivity() {
346350
}
347351

348352
private fun setImage(uri: Uri) {
349-
runAsync("Loading") {
353+
runAsync(MSG_LOAD) {
350354
runOnUiThread {
351355
setEditMode(true)
352356
}
@@ -413,82 +417,92 @@ class MainActivity : AppCompatActivity() {
413417
return convertToDepth(imageRGB, settings.engineDepth)
414418
}
415419

416-
private fun saveImage() {
420+
private fun saveImageAsync() {
421+
if (inputImage.empty()) return
422+
423+
warpImageAsync()
417424
if (outputImage.empty()) return
418425

419-
runAsync("Saving") {
426+
setBusyDialogTitleAsync(MSG_SAVE)
420427

421-
val outputExtension = settings.outputExtension()
428+
val outputExtension = settings.outputExtension()
422429

423-
try {
424-
var fileName = "${outputName}.${outputExtension}"
425-
var fileFullPath = Settings.SAVE_FOLDER + "/" + fileName
426-
var counter = 0
427-
while (File(fileFullPath).exists() && counter < 998) {
428-
counter++
429-
val counterStr = "%03d".format(counter)
430-
fileName = "${outputName}_${counterStr}.${outputExtension}"
431-
fileFullPath = Settings.SAVE_FOLDER + "/" + fileName
432-
}
430+
try {
431+
var fileName = "${outputName}.${outputExtension}"
432+
var fileFullPath = Settings.SAVE_FOLDER + "/" + fileName
433+
var counter = 0
434+
while (File(fileFullPath).exists() && counter < 998) {
435+
counter++
436+
val counterStr = "%03d".format(counter)
437+
fileName = "${outputName}_${counterStr}.${outputExtension}"
438+
fileFullPath = Settings.SAVE_FOLDER + "/" + fileName
439+
}
433440

434-
val outputRGB = Mat()
435-
cvtColor(outputImage, outputRGB, COLOR_BGR2RGB)
441+
val outputRGB = Mat()
442+
cvtColor(outputImage, outputRGB, COLOR_BGR2RGB)
436443

437-
var outputDepth = Settings.DEPTH_AUTO
444+
var outputDepth = Settings.DEPTH_AUTO
438445

439-
if (Settings.OUTPUT_TYPE_JPEG == settings.outputType
440-
|| (Settings.OUTPUT_TYPE_PNG == settings.outputType && Settings.DEPTH_8_BITS == settings.pngDepth)
441-
|| (Settings.OUTPUT_TYPE_TIFF == settings.outputType && Settings.DEPTH_8_BITS == settings.tiffDepth)
442-
) {
443-
outputDepth = Settings.DEPTH_8_BITS
444-
} else if ((Settings.OUTPUT_TYPE_PNG == settings.outputType && Settings.DEPTH_16_BITS == settings.pngDepth)
445-
|| (Settings.OUTPUT_TYPE_TIFF == settings.outputType && Settings.DEPTH_16_BITS == settings.tiffDepth)
446-
) {
447-
outputDepth = Settings.DEPTH_16_BITS
448-
}
446+
if (Settings.OUTPUT_TYPE_JPEG == settings.outputType
447+
|| (Settings.OUTPUT_TYPE_PNG == settings.outputType && Settings.DEPTH_8_BITS == settings.pngDepth)
448+
|| (Settings.OUTPUT_TYPE_TIFF == settings.outputType && Settings.DEPTH_8_BITS == settings.tiffDepth)
449+
) {
450+
outputDepth = Settings.DEPTH_8_BITS
451+
} else if ((Settings.OUTPUT_TYPE_PNG == settings.outputType && Settings.DEPTH_16_BITS == settings.pngDepth)
452+
|| (Settings.OUTPUT_TYPE_TIFF == settings.outputType && Settings.DEPTH_16_BITS == settings.tiffDepth)
453+
) {
454+
outputDepth = Settings.DEPTH_16_BITS
455+
}
449456

450-
File(fileFullPath).parentFile?.mkdirs()
457+
File(fileFullPath).parentFile?.mkdirs()
451458

452-
val outputParams = MatOfInt()
459+
val outputParams = MatOfInt()
453460

454-
if (Settings.OUTPUT_TYPE_JPEG == settings.outputType) {
455-
outputParams.fromArray(Imgcodecs.IMWRITE_JPEG_QUALITY, settings.jpegQuality)
456-
}
461+
if (Settings.OUTPUT_TYPE_JPEG == settings.outputType) {
462+
outputParams.fromArray(Imgcodecs.IMWRITE_JPEG_QUALITY, settings.jpegQuality)
463+
}
457464

458-
Imgcodecs.imwrite(fileFullPath, convertToDepth(outputRGB, outputDepth), outputParams)
465+
Imgcodecs.imwrite(fileFullPath, convertToDepth(outputRGB, outputDepth), outputParams)
459466

460-
inputUri?.let { uri ->
461-
ExifTools.copyExif( contentResolver, uri, fileFullPath )
462-
}
463-
464-
runOnUiThread {
465-
//Add it to gallery
466-
val values = ContentValues()
467-
@Suppress("DEPRECATION")
468-
values.put(MediaStore.Images.Media.DATA, fileFullPath)
469-
values.put(MediaStore.Images.Media.MIME_TYPE, "image/${outputExtension}")
470-
contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values)
471-
472-
val perspectivePoints = binding.imageEdit.getPerspective()
473-
settings.prevWidth = outputImage.width()
474-
settings.prevHeight = outputImage.height()
475-
settings.prevLeftTopX = perspectivePoints.pointLeftTop.x
476-
settings.prevLeftTopY = perspectivePoints.pointLeftTop.y
477-
settings.prevRightTopX = perspectivePoints.pointRightTop.x
478-
settings.prevRightTopY = perspectivePoints.pointRightTop.y
479-
settings.prevLeftBottomX = perspectivePoints.pointLeftBottom.x
480-
settings.prevLeftBottomY = perspectivePoints.pointLeftBottom.y
481-
settings.prevRightBottomX = perspectivePoints.pointRightBottom.x
482-
settings.prevRightBottomY = perspectivePoints.pointRightBottom.y
483-
settings.saveProperties()
484-
485-
menuPrevPerspective?.isEnabled = true
486-
}
467+
inputUri?.let { uri ->
468+
ExifTools.copyExif( contentResolver, uri, fileFullPath )
469+
}
487470

488-
showToast("Saved to: $fileName")
489-
} catch (e: Exception) {
490-
showToast("Failed to save")
471+
runOnUiThread {
472+
//Add it to gallery
473+
val values = ContentValues()
474+
@Suppress("DEPRECATION")
475+
values.put(MediaStore.Images.Media.DATA, fileFullPath)
476+
values.put(MediaStore.Images.Media.MIME_TYPE, "image/${outputExtension}")
477+
contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values)
478+
479+
val perspectivePoints = binding.imageEdit.getPerspective()
480+
settings.prevWidth = outputImage.width()
481+
settings.prevHeight = outputImage.height()
482+
settings.prevLeftTopX = perspectivePoints.pointLeftTop.x
483+
settings.prevLeftTopY = perspectivePoints.pointLeftTop.y
484+
settings.prevRightTopX = perspectivePoints.pointRightTop.x
485+
settings.prevRightTopY = perspectivePoints.pointRightTop.y
486+
settings.prevLeftBottomX = perspectivePoints.pointLeftBottom.x
487+
settings.prevLeftBottomY = perspectivePoints.pointLeftBottom.y
488+
settings.prevRightBottomX = perspectivePoints.pointRightBottom.x
489+
settings.prevRightBottomY = perspectivePoints.pointRightBottom.y
490+
settings.saveProperties()
491+
492+
menuPrevPerspective?.isEnabled = true
491493
}
494+
495+
showToast("Saved to: $fileName")
496+
} catch (e: Exception) {
497+
showToast("Failed to save")
498+
}
499+
}
500+
501+
private fun saveImage() {
502+
if (inputImage.empty()) return
503+
504+
runAsync(MSG_SAVE) {
505+
saveImageAsync()
492506
}
493507
}
494508

@@ -503,42 +517,57 @@ class MainActivity : AppCompatActivity() {
503517
}
504518
}
505519

506-
private fun warpImage() {
520+
private fun setBusyDialogTitleAsync(title: String) {
521+
runOnUiThread {
522+
BusyDialog.setTitle(title)
523+
}
524+
}
525+
526+
private fun warpImageAsync() {
507527
if (inputImage.empty()) return
508528
if (!outputImage.empty()) return
509529

510-
runAsync( "Warping") {
511-
val perspectivePoints = binding.imageEdit.getPerspective()
512-
513-
val srcMat = Mat(4, 1, CV_32FC2)
514-
srcMat.put(
515-
0, 0,
516-
perspectivePoints.pointLeftTop.x.toDouble(), perspectivePoints.pointLeftTop.y.toDouble(),
517-
perspectivePoints.pointRightTop.x.toDouble(), perspectivePoints.pointRightTop.y.toDouble(),
518-
perspectivePoints.pointRightBottom.x.toDouble(), perspectivePoints.pointRightBottom.y.toDouble(),
519-
perspectivePoints.pointLeftBottom.x.toDouble(), perspectivePoints.pointLeftBottom.y.toDouble(),
520-
)
521-
522-
val destLeft = (perspectivePoints.pointLeftTop.x + perspectivePoints.pointLeftBottom.x) / 2.0
523-
val destRight = (perspectivePoints.pointRightTop.x + perspectivePoints.pointRightBottom.x) / 2.0
524-
val destTop = (perspectivePoints.pointLeftTop.y + perspectivePoints.pointRightTop.y) / 2.0
525-
val destBottom = (perspectivePoints.pointLeftBottom.y + perspectivePoints.pointRightBottom.y) / 2.0
526-
527-
val destMat = Mat(4, 1, CV_32FC2)
528-
destMat.put(
529-
0, 0,
530-
destLeft, destTop,
531-
destRight, destTop,
532-
destRight, destBottom,
533-
destLeft, destBottom
534-
)
535-
536-
val perspectiveMat = getPerspectiveTransform(srcMat, destMat)
537-
warpPerspective(inputImage, outputImage, perspectiveMat, inputImage.size(), INTER_LANCZOS4)
530+
setBusyDialogTitleAsync(MSG_WARP)
538531

539-
runOnUiThread {
540-
binding.imagePreview.setBitmap(matToBitmap(outputImage))
541-
}
532+
val perspectivePoints = binding.imageEdit.getPerspective()
533+
534+
val srcMat = Mat(4, 1, CV_32FC2)
535+
srcMat.put(
536+
0, 0,
537+
perspectivePoints.pointLeftTop.x.toDouble(), perspectivePoints.pointLeftTop.y.toDouble(),
538+
perspectivePoints.pointRightTop.x.toDouble(), perspectivePoints.pointRightTop.y.toDouble(),
539+
perspectivePoints.pointRightBottom.x.toDouble(), perspectivePoints.pointRightBottom.y.toDouble(),
540+
perspectivePoints.pointLeftBottom.x.toDouble(), perspectivePoints.pointLeftBottom.y.toDouble(),
541+
)
542+
543+
val destLeft = (perspectivePoints.pointLeftTop.x + perspectivePoints.pointLeftBottom.x) / 2.0
544+
val destRight = (perspectivePoints.pointRightTop.x + perspectivePoints.pointRightBottom.x) / 2.0
545+
val destTop = (perspectivePoints.pointLeftTop.y + perspectivePoints.pointRightTop.y) / 2.0
546+
val destBottom = (perspectivePoints.pointLeftBottom.y + perspectivePoints.pointRightBottom.y) / 2.0
547+
548+
val destMat = Mat(4, 1, CV_32FC2)
549+
destMat.put(
550+
0, 0,
551+
destLeft, destTop,
552+
destRight, destTop,
553+
destRight, destBottom,
554+
destLeft, destBottom
555+
)
556+
557+
val perspectiveMat = getPerspectiveTransform(srcMat, destMat)
558+
warpPerspective(inputImage, outputImage, perspectiveMat, inputImage.size(), INTER_LANCZOS4)
559+
560+
runOnUiThread {
561+
binding.imagePreview.setBitmap(matToBitmap(outputImage))
562+
}
563+
}
564+
565+
private fun warpImage() {
566+
if (inputImage.empty()) return
567+
if (!outputImage.empty()) return
568+
569+
runAsync(MSG_WARP) {
570+
warpImageAsync()
542571
}
543572
}
544573

@@ -708,7 +737,7 @@ class MainActivity : AppCompatActivity() {
708737
private fun autoDetectPerspective() {
709738
if (inputImage.empty()) return
710739

711-
runAsync("Auto detect") {
740+
runAsync(MSG_AUTO_DETECT) {
712741
autoDetectPerspectiveAsync()
713742
}
714743
}

0 commit comments

Comments
 (0)