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