Rely on PDFBox-Android to reduce the size of generated PDFs
This commit is contained in:
@@ -60,6 +60,7 @@ dependencies {
|
||||
implementation(libs.litert.support)
|
||||
implementation(libs.litert.metadata)
|
||||
implementation(libs.opencv)
|
||||
implementation(libs.pdfbox)
|
||||
|
||||
testImplementation(libs.junit)
|
||||
testImplementation(libs.assertj)
|
||||
|
||||
@@ -2,7 +2,6 @@ package org.mydomain.myscan
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.graphics.Bitmap
|
||||
import android.media.MediaScannerConnection
|
||||
import android.os.Bundle
|
||||
import android.os.Environment
|
||||
@@ -32,7 +31,7 @@ class MainActivity : ComponentActivity() {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
initOpenCV()
|
||||
initLibraries()
|
||||
val viewModel: MainViewModel by viewModels { MainViewModel.getFactory(this) }
|
||||
enableEdgeToEdge()
|
||||
setContent {
|
||||
@@ -68,19 +67,15 @@ class MainActivity : ComponentActivity() {
|
||||
viewModel: MainViewModel,
|
||||
context: Context
|
||||
): () -> Unit = {
|
||||
val document = viewModel.createPdf()
|
||||
val outputDir = File(cacheDir, "pdfs").apply { mkdirs() }
|
||||
val outputFile = File(outputDir, "scan_${System.currentTimeMillis()}.pdf")
|
||||
var success = true
|
||||
try {
|
||||
FileOutputStream(outputFile).use { outputStream ->
|
||||
document.writeTo(outputStream)
|
||||
}
|
||||
val fileOutputStream = FileOutputStream(outputFile)
|
||||
viewModel.createPdf(fileOutputStream)
|
||||
} catch (_: IOException) {
|
||||
Toast.makeText(context, "Failed to share PDF", Toast.LENGTH_SHORT).show()
|
||||
success = false
|
||||
} finally {
|
||||
document.close()
|
||||
}
|
||||
if (success) {
|
||||
val uri = FileProvider.getUriForFile(
|
||||
@@ -101,13 +96,12 @@ class MainActivity : ComponentActivity() {
|
||||
viewModel: MainViewModel,
|
||||
context: Context
|
||||
): () -> Unit = {
|
||||
val document = viewModel.createPdf()
|
||||
try {
|
||||
val downloadsDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
|
||||
if (!downloadsDir.exists()) downloadsDir.mkdirs()
|
||||
val file = File(downloadsDir, "scan_${System.currentTimeMillis()}.pdf")
|
||||
val outputStream = FileOutputStream(file)
|
||||
document.writeTo(outputStream)
|
||||
viewModel.createPdf(outputStream)
|
||||
outputStream.flush()
|
||||
outputStream.close()
|
||||
|
||||
@@ -119,12 +113,12 @@ class MainActivity : ComponentActivity() {
|
||||
} catch (e: Exception) {
|
||||
Log.e("MyScan", "Failed to save PDF", e)
|
||||
Toast.makeText(context, "Failed to save PDF", Toast.LENGTH_SHORT).show()
|
||||
} finally {
|
||||
document.close()
|
||||
}
|
||||
}
|
||||
|
||||
private fun initOpenCV() {
|
||||
private fun initLibraries() {
|
||||
com.tom_roush.pdfbox.android.PDFBoxResourceLoader.init(applicationContext)
|
||||
|
||||
if (!OpenCVLoader.initLocal()) {
|
||||
Log.e("OpenCV", "Initialization failed")
|
||||
} else {
|
||||
|
||||
@@ -19,6 +19,7 @@ import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.io.OutputStream
|
||||
|
||||
class MainViewModel(
|
||||
private val imageSegmentationService: ImageSegmentationService,
|
||||
@@ -128,9 +129,9 @@ class MainViewModel(
|
||||
return BitmapFactory.decodeByteArray(bytes, 0, bytes.size)
|
||||
}
|
||||
|
||||
fun createPdf(): PdfDocument {
|
||||
fun createPdf(outputStream: OutputStream) {
|
||||
val jpegs = imageRepository.imageIds().asSequence()
|
||||
.map { id -> imageRepository.getContent(id) }
|
||||
return createPdfFromJpegs(jpegs)
|
||||
writePdfFromJpegs(jpegs, outputStream)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,21 +1,28 @@
|
||||
package org.mydomain.myscan
|
||||
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.BitmapFactory
|
||||
import android.graphics.pdf.PdfDocument
|
||||
import androidx.core.graphics.scale
|
||||
import com.tom_roush.pdfbox.pdmodel.PDDocument
|
||||
import com.tom_roush.pdfbox.pdmodel.PDPage
|
||||
import com.tom_roush.pdfbox.pdmodel.PDPageContentStream
|
||||
import com.tom_roush.pdfbox.pdmodel.PDPageContentStream.AppendMode
|
||||
import com.tom_roush.pdfbox.pdmodel.common.PDRectangle
|
||||
import com.tom_roush.pdfbox.pdmodel.graphics.image.JPEGFactory
|
||||
import java.io.OutputStream
|
||||
import kotlin.math.max
|
||||
|
||||
fun createPdfFromJpegs (jpegs: Sequence<ByteArray>): PdfDocument {
|
||||
val document = PdfDocument()
|
||||
for ((index, jpegBytes) in jpegs.withIndex()) {
|
||||
val bitmap = BitmapFactory.decodeByteArray(jpegBytes, 0, jpegBytes.size)
|
||||
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)
|
||||
fun writePdfFromJpegs(jpegs: Sequence<ByteArray>, outputStream: OutputStream) {
|
||||
PDDocument().use { document ->
|
||||
for (jpegBytes in jpegs) {
|
||||
val image = JPEGFactory.createFromByteArray(document, jpegBytes)
|
||||
val page = PDPage(PDRectangle(image.width.toFloat(), image.height.toFloat()))
|
||||
document.addPage(page)
|
||||
val contentStream = PDPageContentStream(document, page, AppendMode.OVERWRITE, false)
|
||||
contentStream.drawImage(image, 0f, 0f)
|
||||
contentStream.close()
|
||||
}
|
||||
document.save(outputStream)
|
||||
}
|
||||
return document
|
||||
}
|
||||
|
||||
fun resizeImage(original: Bitmap): Bitmap {
|
||||
|
||||
Reference in New Issue
Block a user