Save PDF and share it

This commit is contained in:
Pierre-Yves Nicolas
2025-05-31 13:42:24 +02:00
parent 453923b42d
commit f8b9f47782
5 changed files with 86 additions and 2 deletions

View File

@@ -28,6 +28,15 @@
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
</application>
</manifest>

View File

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

View File

@@ -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<Bitmap>, 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()
}
}

View File

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

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<cache-path
name="pdfs"
path="pdfs/" />
</paths>