diff --git a/android/app/src/main/java/com/lensapp/PdfGeneratorModule.kt b/android/app/src/main/java/com/lensapp/PdfGeneratorModule.kt index f3674ee..fde28bd 100644 --- a/android/app/src/main/java/com/lensapp/PdfGeneratorModule.kt +++ b/android/app/src/main/java/com/lensapp/PdfGeneratorModule.kt @@ -28,6 +28,61 @@ class PdfGeneratorModule(private val reactContext: ReactApplicationContext) : return out } + @ReactMethod + fun generateIdCard(imagePaths: ReadableArray, fileName: String, matrix: ReadableArray, promise: Promise) { + try { + val count = imagePaths.size() + if (count == 0) throw Exception("No images provided") + val outDir = File(reactContext.filesDir, "pdfs").also { it.mkdirs() } + val outFile = File(outDir, "$fileName.pdf") + val doc = PdfDocument() + + // A4 portrait: 595 x 842 points + val pageWidth = 595 + val pageHeight = 842 + val slotW = 250 + val slotH = 180 + val gap = 16 + val totalW = slotW * 2 + gap + val startX = (pageWidth - totalW) / 2f + val startY = (pageHeight - slotH) / 2f + + val numPages = (count + 1) / 2 + for (p in 0 until numPages) { + val pageInfo = PdfDocument.PageInfo.Builder(pageWidth, pageHeight, p + 1).create() + val page = doc.startPage(pageInfo) + + for (slot in 0 until 2) { + val imgIndex = p * 2 + slot + if (imgIndex >= count) break + + val path = imagePaths.getString(imgIndex)!!.removePrefix("file://") + val raw = BitmapFactory.decodeFile(path) ?: throw Exception("Failed to decode image: $path") + val bitmap = applyFilter(raw, matrix) + if (raw !== bitmap) raw.recycle() + + val slotLeft = startX + slot * (slotW + gap) + val scale = minOf(slotW.toFloat() / bitmap.width, slotH.toFloat() / bitmap.height) + val scaledW = bitmap.width * scale + val scaledH = bitmap.height * scale + val left = slotLeft + (slotW - scaledW) / 2f + val top = startY + (slotH - scaledH) / 2f + + page.canvas.drawBitmap(bitmap, null, RectF(left, top, left + scaledW, top + scaledH), null) + bitmap.recycle() + } + + doc.finishPage(page) + } + + FileOutputStream(outFile).use { doc.writeTo(it) } + doc.close() + promise.resolve("file://${outFile.absolutePath}") + } catch (e: Exception) { + promise.reject("PDF_ERROR", e.message, e) + } + } + @ReactMethod fun generate(imagePaths: ReadableArray, fileName: String, matrix: ReadableArray, promise: Promise) { try { diff --git a/patches/react-native-document-scanner-plugin+2.0.4.patch b/patches/react-native-document-scanner-plugin+2.0.4.patch index e7abe22..9b145b3 100644 --- a/patches/react-native-document-scanner-plugin+2.0.4.patch +++ b/patches/react-native-document-scanner-plugin+2.0.4.patch @@ -1,3 +1,16 @@ +diff --git a/node_modules/react-native-document-scanner-plugin/android/src/main/java/com/documentscanner/DocumentScannerModule.kt b/node_modules/react-native-document-scanner-plugin/android/src/main/java/com/documentscanner/DocumentScannerModule.kt +index fbb6836..e75b6b2 100644 +--- a/node_modules/react-native-document-scanner-plugin/android/src/main/java/com/documentscanner/DocumentScannerModule.kt ++++ b/node_modules/react-native-document-scanner-plugin/android/src/main/java/com/documentscanner/DocumentScannerModule.kt +@@ -51,7 +51,7 @@ class DocumentScannerModule(reactContext: ReactApplicationContext) : + + val documentScannerOptionsBuilder = GmsDocumentScannerOptions.Builder() + .setResultFormats(GmsDocumentScannerOptions.RESULT_FORMAT_JPEG) +- .setScannerMode(GmsDocumentScannerOptions.SCANNER_MODE_FULL) ++ .setScannerMode(GmsDocumentScannerOptions.SCANNER_MODE_BASE) + + if (options.hasKey("maxNumDocuments")) { + documentScannerOptionsBuilder.setPageLimit( diff --git a/node_modules/react-native-document-scanner-plugin/android/src/main/java/com/documentscanner/DocumentScannerPackage.kt b/node_modules/react-native-document-scanner-plugin/android/src/main/java/com/documentscanner/DocumentScannerPackage.kt index 84f3fec..54a8f53 100644 --- a/node_modules/react-native-document-scanner-plugin/android/src/main/java/com/documentscanner/DocumentScannerPackage.kt diff --git a/src/screens/ViewerScreen.tsx b/src/screens/ViewerScreen.tsx index 09ed081..241317b 100644 --- a/src/screens/ViewerScreen.tsx +++ b/src/screens/ViewerScreen.tsx @@ -16,7 +16,7 @@ import { import Share from 'react-native-share'; import {ColorMatrix} from 'react-native-color-matrix-image-filters'; import {ScannedDocument} from '../types'; -import {generatePdf} from '../utils/generatePdf'; +import {generatePdf, generateIdCardPdf} from '../utils/generatePdf'; import {getFilterMatrix} from '../utils/filterMatrices'; import {useTheme} from '../theme'; @@ -36,6 +36,25 @@ export default function ViewerScreen({document, onBack, onDelete, onRename}: Pro const [renaming, setRenaming] = useState(false); const [renameText, setRenameText] = useState(''); + const shareIdCard = async () => { + setGenerating(true); + await new Promise(resolve => setTimeout(resolve, 0)); + try { + const label = `${document.name} — ID Card`; + const pdfPath = await generateIdCardPdf(document.pages, label, document.filter); + await Share.open({ + title: label, + type: 'application/pdf', + url: pdfPath, + failOnCancel: false, + }); + } catch (err: any) { + Alert.alert('Share failed', err?.message ?? 'Could not generate PDF.'); + } finally { + setGenerating(false); + } + }; + const sharePdf = async (pageIndices?: number[]) => { setGenerating(true); await new Promise(resolve => setTimeout(resolve, 0)); @@ -132,6 +151,10 @@ export default function ViewerScreen({document, onBack, onDelete, onRename}: Pro 📄 Share All + + 🪪 + ID Card + {setRenameText(document.name); setRenaming(true);}}> diff --git a/src/utils/generatePdf.ts b/src/utils/generatePdf.ts index 160972e..34f1997 100644 --- a/src/utils/generatePdf.ts +++ b/src/utils/generatePdf.ts @@ -9,3 +9,9 @@ export async function generatePdf(pages: ScannedPage[], name: string, filter: Fi const fileName = name.replace(/[^a-z0-9_\-]/gi, '_'); return PdfGenerator.generate(imagePaths, fileName, getFilterMatrix(filter)); } + +export async function generateIdCardPdf(pages: ScannedPage[], name: string, filter: FilterMode = 'original'): Promise { + const imagePaths = pages.map(p => p.uri); + const fileName = name.replace(/[^a-z0-9_\-]/gi, '_'); + return PdfGenerator.generateIdCard(imagePaths, fileName, getFilterMatrix(filter)); +}