From f8b9f47782de5a42d5065c72366ee3131f7bdd31 Mon Sep 17 00:00:00 2001
From: Pierre-Yves Nicolas <6371790+pynicolas@users.noreply.github.com>
Date: Sat, 31 May 2025 13:42:24 +0200
Subject: [PATCH] Save PDF and share it
---
app/src/main/AndroidManifest.xml | 9 ++++++
.../java/org/mydomain/myscan/MainActivity.kt | 32 ++++++++++++++++++-
.../java/org/mydomain/myscan/PdfGeneration.kt | 29 +++++++++++++++++
.../org/mydomain/myscan/view/PagePreview.kt | 12 ++++++-
app/src/main/res/xml/file_paths.xml | 6 ++++
5 files changed, 86 insertions(+), 2 deletions(-)
create mode 100644 app/src/main/java/org/mydomain/myscan/PdfGeneration.kt
create mode 100644 app/src/main/res/xml/file_paths.xml
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index eae1911..1ff3736 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -28,6 +28,15 @@
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/org/mydomain/myscan/MainActivity.kt b/app/src/main/java/org/mydomain/myscan/MainActivity.kt
index 5d07335..c861786 100644
--- a/app/src/main/java/org/mydomain/myscan/MainActivity.kt
+++ b/app/src/main/java/org/mydomain/myscan/MainActivity.kt
@@ -1,7 +1,11 @@
package org.mydomain.myscan
+import android.content.Context
+import android.content.Intent
+import android.graphics.Bitmap
import android.os.Bundle
import android.util.Log
+import android.widget.Toast
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
@@ -17,13 +21,16 @@ import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
+import androidx.core.content.FileProvider
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import org.mydomain.myscan.ui.theme.MyScanTheme
import org.mydomain.myscan.view.CameraScreen
import org.mydomain.myscan.view.PagePreviewScreen
import org.opencv.android.OpenCVLoader
+import java.io.File
class MainActivity : ComponentActivity() {
@@ -37,6 +44,7 @@ class MainActivity : ComponentActivity() {
val currentScreen by viewModel.currentScreen.collectAsState()
// TODO should uiState own currentScreen?
val uiState by viewModel.uiState.collectAsStateWithLifecycle()
+ val context = LocalContext.current
MyScanTheme {
Scaffold { innerPadding ->
Column {
@@ -51,7 +59,8 @@ class MainActivity : ComponentActivity() {
PagePreviewScreen (
image = screen.image,
isProcessing = screen.isProcessing,
- onBackPressed = { viewModel.navigateTo(Screen.Camera) }
+ onBackPressed = { viewModel.navigateTo(Screen.Camera) },
+ onSavePressed = createPdfAndShare(context)
)
}
}
@@ -61,6 +70,27 @@ class MainActivity : ComponentActivity() {
}
}
+ private fun createPdfAndShare(context: Context): (Bitmap) -> Unit = { bitmap ->
+ val outputDir = File(cacheDir, "pdfs").apply { mkdirs() }
+ val outputFile = File(outputDir, "scan_${System.currentTimeMillis()}.pdf")
+ val success = createPdfFromBitmaps(listOf(bitmap), outputFile)
+ if (success) {
+ val uri = FileProvider.getUriForFile(
+ context,
+ "${applicationContext.packageName}.fileprovider",
+ outputFile
+ )
+ val shareIntent = Intent(Intent.ACTION_SEND).apply {
+ type = "application/pdf"
+ putExtra(Intent.EXTRA_STREAM, uri)
+ addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
+ }
+ startActivity(Intent.createChooser(shareIntent, "Share PDF"))
+ } else {
+ Toast.makeText(context, "Failed to save PDF", Toast.LENGTH_SHORT).show()
+ }
+ }
+
private fun initOpenCV() {
if (!OpenCVLoader.initLocal()) {
Log.e("OpenCV", "Initialization failed")
diff --git a/app/src/main/java/org/mydomain/myscan/PdfGeneration.kt b/app/src/main/java/org/mydomain/myscan/PdfGeneration.kt
new file mode 100644
index 0000000..5500945
--- /dev/null
+++ b/app/src/main/java/org/mydomain/myscan/PdfGeneration.kt
@@ -0,0 +1,29 @@
+package org.mydomain.myscan
+
+import android.graphics.Bitmap
+import android.graphics.pdf.PdfDocument
+import android.util.Log
+import java.io.File
+import java.io.FileOutputStream
+import java.io.IOException
+
+fun createPdfFromBitmaps(bitmaps: List, outputFile: File): Boolean {
+ val document = PdfDocument()
+ try {
+ for ((index, bitmap) in bitmaps.withIndex()) {
+ val pageInfo = PdfDocument.PageInfo.Builder(bitmap.width, bitmap.height, index + 1).create()
+ val page = document.startPage(pageInfo)
+ page.canvas.drawBitmap(bitmap, 0f, 0f, null)
+ document.finishPage(page)
+ }
+ FileOutputStream(outputFile).use { outputStream ->
+ document.writeTo(outputStream)
+ }
+ return true
+ } catch (e: IOException) {
+ Log.e("MyScan", "Error writing PDF: ${e.message}")
+ return false
+ } finally {
+ document.close()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/org/mydomain/myscan/view/PagePreview.kt b/app/src/main/java/org/mydomain/myscan/view/PagePreview.kt
index c340e3d..4dc2e4c 100644
--- a/app/src/main/java/org/mydomain/myscan/view/PagePreview.kt
+++ b/app/src/main/java/org/mydomain/myscan/view/PagePreview.kt
@@ -7,6 +7,7 @@ import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowBack
+import androidx.compose.material3.Button
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
@@ -22,7 +23,8 @@ import androidx.compose.ui.unit.dp
fun PagePreviewScreen(
image: Bitmap?,
isProcessing: Boolean,
- onBackPressed: () -> Unit
+ onBackPressed: () -> Unit,
+ onSavePressed: (Bitmap) -> Unit,
) {
Box(modifier = Modifier.fillMaxSize()) {
when {
@@ -39,6 +41,14 @@ fun PagePreviewScreen(
modifier = Modifier.fillMaxSize(),
contentScale = ContentScale.Fit
)
+ Button (
+ onClick = { onSavePressed(image) },
+ modifier = Modifier
+ .align(Alignment.BottomCenter)
+ .padding(16.dp)
+ ) {
+ Text("Save as PDF")
+ }
}
else -> {
Text(
diff --git a/app/src/main/res/xml/file_paths.xml b/app/src/main/res/xml/file_paths.xml
new file mode 100644
index 0000000..ac862b7
--- /dev/null
+++ b/app/src/main/res/xml/file_paths.xml
@@ -0,0 +1,6 @@
+
+
+
+