While ScanFlow can automatically generate a PDF during the scanning process, there are scenarios where you might want to:
This guide shows how to use the SDK’s PDF generation capabilities with images captured from ScanFlow.
First, configure ScanFlow to return only the scanned images. We still use the multiPage
option because we want to scan multiple pages, but we set the multiPageFormat
to “none” so no multi-page document is generated.
// Configure ScanFlow without PDF generation
let configuration = GSKScanFlowConfiguration()
configuration.multiPage = true // Scan multiple pages
configuration.multiPageFormat = .none // Disable automatic PDF
configuration.jpegQuality = 0.9 // High quality for post-processing
// Start scanning
let scanFlow = GSKScanFlow(configuration: configuration)
scanFlow.start(from: self, onSuccess: { result in
// Result contains scanned pages but no PDF
let scannedPages = result.scannedPages
self.processAndCreatePDF(from: scannedPages)
}, failure: { error in
print("Scanning failed: \(error.localizedDescription)")
})
// Configure ScanFlow without PDF generation
val configuration = ScanConfiguration().apply {
multiPage = true
multiPageFormat = none // Disable automatic PDF
}
// Start scanning
ScanFlow.scanWithConfiguration(this, configuration)
// Handle result
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
try {
val result = ScanFlow.getScanResultFromActivityResult(data)
// Result contains pages but no PDF
val pages = result.pages
processAndCreatePDF(pages)
} catch (e: Exception) {
Log.e("Scanner", "Scanning failed", e)
}
}
// Configure without PDF generation
const configuration = {
multiPage: true,
multiPageFormat: 'none', // Don't generate PDF
};
try {
const result = await RNGeniusScan.scanWithConfiguration(configuration);
// Result contains individual scans but no PDF
const { scans } = result;
await processAndCreatePDF(scans);
} catch (error) {
console.error("Scanning failed:", error);
}
// Configure without PDF generation
var configuration = {
'multiPage': true,
'multiPageFormat': 'none', // Don't generate PDF
};
try {
var result = await FlutterGeniusScan.scanWithConfiguration(configuration);
// Result contains individual scans but no PDF
List<dynamic> scans = result['scans'];
await processAndCreatePDF(scans);
} catch (error) {
print("Scanning failed: $error");
}
// Configure without PDF generation
const configuration = {
multiPage: true,
multiPageFormat: 'none', // Don't generate PDF
};
cordova.plugins.GeniusScan.scanWithConfiguration(
configuration,
function(result) {
// Result contains individual scans but no PDF
const scans = result.scans;
processAndCreatePDF(scans);
},
function(error) {
console.error("Scanning failed:", error);
}
);
After receiving the scanned images from ScanFlow, you can process them before PDF generation:
func processAndCreatePDF(from scannedPages: [GSKScanResult]) {
let processedImages = scannedPages.compactMap { page -> (path: String, size: GSKPDFSize)? in
let imagePath = page.enhancedImagePath
guard let image = UIImage(contentsOfFile: imagePath) else {
return nil
}
// Example: Apply custom filter
let processedImage = applyCustomFilter(to: image)
// Example: Add watermark
let watermarkedImage = addWatermark(to: processedImage)
// Save processed image
let processedPath = saveProcessedImage(watermarkedImage)
return (path: processedPath, size: .A4)
}
// Now generate PDF with processed images
generatePDF(from: processedImages)
}
func applyCustomFilter(to image: UIImage) -> UIImage {
// Your custom image processing logic
// Example: Increase contrast, adjust brightness, etc.
return image
}
func addWatermark(to image: UIImage) -> UIImage {
// Add watermark, timestamp, or annotations
return image
}
fun processAndCreatePDF(pages: List<Page>) {
val processedImages = mutableListOf<Pair<String, PDFPage.Size>>()
pages.forEach { page ->
val imagePath = page.enhancedImage.path
// Load and process the image
val bitmap = BitmapFactory.decodeFile(imagePath)
// Example: Apply custom filter
val processedBitmap = applyCustomFilter(bitmap)
// Example: Add watermark
val watermarkedBitmap = addWatermark(processedBitmap)
// Save processed image
val processedPath = saveProcessedImage(watermarkedBitmap)
// Add to PDF pages
processedImages.add(
processedPath to PDFPage.Size.A4
)
}
// Now generate PDF with processed images
generatePDF(processedImages)
}
fun applyCustomFilter(bitmap: Bitmap): Bitmap {
// Your custom image processing logic
// Example: Increase contrast, adjust brightness, etc.
return bitmap
}
fun addWatermark(bitmap: Bitmap): Bitmap {
// Add watermark, timestamp, or annotations
return bitmap
}
After processing, use the SDK’s PDF generator to create the final document:
func generatePDF(from processedImages: [(path: String, size: GSKPDFSize)]) {
// Create PDF pages
let pdfPages = processedImages.map { (imagePath, pageSize) in
GSKPDFPage(
filePath: imagePath,
inchesSize: pageSize
)
}
// Configure PDF metadata
let document = GSKPDFDocument(
title: "Processed Document",
password: nil, // Add password protection if needed
keywords: ["scanned", "processed"],
pages: pdfPages
)
// Set output path
let outputPath = NSTemporaryDirectory()
.appendingPathComponent("processed_document.pdf")
// Configure generator
let configuration = GSKDocumentGeneratorConfiguration(
outputFilePath: outputPath
)
// Generate PDF
do {
try GSKDocumentGenerator().generate(
document,
configuration: configuration
)
print("PDF generated at: \(outputPath)")
// Share or save the PDF
sharePDF(at: outputPath)
} catch {
print("PDF generation failed: \(error)")
}
}
fun generatePDF(processedImages: List<Pair<String, PDFPage.Size>>) {
// Create PDF pages
val pdfPages = processedImages.map { (imagePath, pageSize) ->
PDFPage(imagePath, pageSize)
}
// Configure PDF metadata
val document = PDFDocument(
pdfPages,
"Processed Document", // title
null, // password - add if needed
listOf("scanned", "processed") // keywords
)
// Set output file
val outputFile = File(
context.cacheDir,
"processed_document.pdf"
)
// Configure generator
val configuration = DocumentGenerator.Configuration(outputFile)
// Generate PDF
try {
DocumentGenerator(context).generatePDFDocument(
document,
configuration
)
Log.d("PDF", "Generated at: ${outputFile.absolutePath}")
// Share or save the PDF
sharePDF(outputFile)
} catch (e: Exception) {
Log.e("PDF", "Generation failed", e)
}
}
Make your PDF searchable by adding OCR results:
// Perform OCR on processed images
let ocrConfiguration = GSKOCRConfiguration(
languages: ["eng", "fra"],
tessdataPrefixPath: Bundle.main.bundlePath
)
let ocr = GSKOCR(configuration: ocrConfiguration)
// Create PDF pages with OCR
let pdfPages = try processedImages.map { (imagePath, pageSize) in
// Run OCR
let ocrResult = try ocr.recognize(fromImageAtPath: imagePath)
// Create page with text layout
return GSKPDFPage(
filePath: imagePath,
inchesSize: pageSize,
textLayout: ocrResult?.textLayout
)
}
// Generate searchable PDF
let document = GSKPDFDocument(
title: "Searchable Document",
password: nil,
keywords: nil,
pages: pdfPages
)
// Initialize OCR
val tessDataPath = File(context.filesDir, "tessdata").absolutePath
val ocr = OCREngine(tessDataPath, listOf("eng", "fra"))
// Create PDF pages with OCR
val pdfPages = processedImages.map { (imagePath, pageSize) ->
// Run OCR
val ocrResult = ocr.recognizeText(imagePath)
// Create page with text layout
PDFPage(
imagePath = imagePath,
pageSize = pageSize,
textLayout = ocrResult.textLayout // Makes PDF searchable
)
}
// Generate searchable PDF
val document = PDFDocument(
pages = pdfPages,
title = "Searchable Document",
password = null,
keywords = null
)
Control the page size in your generated PDF:
// Predefined sizes
let a4Page = GSKPDFPage(
filePath: imagePath,
inchesSize: .A4
)
let letterPage = GSKPDFPage(
filePath: imagePath,
inchesSize: .letter
)
// Custom size in inches
let customPage = GSKPDFPage(
filePath: imagePath,
inchesSize: GSKPDFSize(width: 8.5, height: 14.0)
)
// Fit to image dimensions
let fitPage = GSKPDFPage(
filePath: imagePath,
inchesSize: .fit // Maintains original image aspect ratio
)
// Predefined sizes
val a4Page = PDFPage(
imagePath,
PDFPage.Size.A4
)
val letterPage = PDFPage(
imagePath,
PDFPage.Size.LETTER
)
// Custom size in inches
val customPage = PDFPage(
imagePath,
PDFPage.Size.Custom(8.5f, 14.0f)
)
// Fit to image dimensions
val fitPage = PDFPage(
imagePath,
PDFPage.Size.FIT // Maintains original image aspect ratio
)
Process multiple documents and create separate PDFs:
func processBatch(scanResults: [GSKScanResult]) {
// Group pages by document
let documents = groupByDocument(scanResults)
for (index, document) in documents.enumerated() {
// Process each document
let processedImages = processDocument(document)
// Generate individual PDF
generatePDF(
from: processedImages,
filename: "document_\(index + 1).pdf"
)
}
}
Protect your PDFs with passwords:
let document = GSKPDFDocument(
title: "Confidential Document",
password: "securePassword123", // User will need this to open PDF
keywords: nil,
pages: pdfPages
)
Add searchable metadata to your PDFs:
let document = GSKPDFDocument(
title: "Invoice #12345",
password: nil,
keywords: ["invoice", "2024", "accounting", customerName],
pages: pdfPages
)
© 2025 The Grizzly Labs. All rights reserved.