@@ -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