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 = 90 // 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 scans = result.scans
self.processAndCreatePDF(from: scans)
}, failure: { error in
print("Scanning failed: \(error.localizedDescription)")
})
// Configure ScanFlow without PDF generation
val configuration = ScanFlowConfiguration().apply {
multiPage = true
multiPageFormat = ScanFlowConfiguration.MultiPageFormat.NONE // Disable automatic PDF
}
// Start scanning
val scanLauncher = registerForActivityResult(ScanActivity.Contract()) { output ->
when (output) {
is FlowOutput.Success -> {
// Result contains pages but no PDF
val pages = output.result.scans.orEmpty()
processAndCreatePDF(pages)
}
is FlowOutput.Error -> {
Log.e("Scanner", "Scanning failed", output.error)
}
}
}
scanLauncher.launch(configuration)
try {
const result = await RNGeniusScan.scanWithConfiguration({
multiPage: true,
multiPageFormat: 'none', // Don't generate PDF
});
// 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);
}
);
import GeniusScan from '@thegrizzlylabs/capacitor-plugin-genius-scan';
try {
const result = await GeniusScan.scanWithConfiguration({
multiPage: true,
multiPageFormat: 'none', // Don't generate PDF
});
// Result contains individual scans but no PDF
const { scans } = result;
await processAndCreatePDF(scans);
} catch (error) {
console.error("Scanning failed:", error);
}
using GeniusScanSDK.ScanFlow;
var scanFlowService = new ScanFlowService();
var configuration = new Dictionary<string, object>
{
["multiPage"] = true,
["multiPageFormat"] = "none"
};
var result = await scanFlowService.ScanDocument(configuration);
// Result contains individual scans but no PDF
var scans = (IList<object>)result["scans"];
await ProcessAndCreatePDF(scans);
After receiving the scanned images from ScanFlow, you can process them before PDF generation:
func processAndCreatePDF(from scans: [GSKScanFlowScan]) {
let processedImages = scans.compactMap { page -> (path: String, size: GSKPDFSize)? in
let imagePath = page.enhancedFilePath
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: GSKPDFSize(width: 8.27, height: 11.7))
}
// 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<ScanFlowResult.Scan>) {
val processedImages = mutableListOf<Pair<File, PDFSize>>()
pages.forEach { page ->
val imagePath = page.enhancedImageFile.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(
File(processedPath) to PDFSize(width = 8.27, height = 11.7)
)
}
// 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,
textLayout: nil
)
}
// Configure PDF metadata
let document = GSKPDFDocument(
title: "Processed Document",
password: nil, // Add password protection if needed
keywords: "scanned, processed",
creationDate: Date(),
lastUpdate: Date(),
pages: pdfPages
)
// Set output path
let outputPath = (NSTemporaryDirectory() as NSString)
.appendingPathComponent("processed_document.pdf")
// Generate PDF
do {
try GSKDocumentGenerator().generate(
document,
configuration: .pdf(outputFilePath: outputPath)
)
print("PDF generated at: \(outputPath)")
// Share or save the PDF
sharePDF(at: outputPath)
} catch {
print("PDF generation failed: \(error)")
}
}
fun generatePDF(processedImages: List<Pair<File, PDFSize>>) {
// Create PDF pages
val pdfPages = processedImages.map { (imageFile, pageSize) ->
PDFPage(imageFile, pageSize)
}
// Configure PDF metadata
val document = PDFDocument(
pages = pdfPages,
title = "Processed Document",
password = null, // Add password protection if needed
keywords = "scanned, processed"
)
// 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)
}
}
import GeniusScan from '@thegrizzlylabs/capacitor-plugin-genius-scan';
async function generatePDF(processedImages) {
// Create PDF pages
const document = {
pages: processedImages.map(imageUrl => ({
imageUrl
}))
};
// Set output file
const outputFileUrl = 'file:///path/to/processed_document.pdf';
// Generate PDF
try {
await GeniusScan.generateDocument(
document,
{ outputFileUrl }
);
console.log("PDF generated at:", outputFileUrl);
// Share or save the PDF
sharePDF(outputFileUrl);
} catch (error) {
console.error("Generation failed:", error);
}
}
Make your PDF searchable by adding OCR results:
let ocrConfiguration = GSKOCRConfiguration.configuration(
languageTags: ["en-US", "fr-FR"]
)
// Create PDF pages with OCR
var pdfPages = [GSKPDFPage]()
for (imagePath, pageSize) in processedImages {
// Run OCR
let ocrResult = try await GSKOCR().recognizeText(
forImageAtPath: imagePath,
configuration: ocrConfiguration,
onProgress: nil
)
// Create page with text layout
pdfPages.append(GSKPDFPage(
filePath: imagePath,
inchesSize: pageSize,
textLayout: ocrResult.textLayout
))
}
// Generate searchable PDF
let document = GSKPDFDocument(
title: "Searchable Document",
password: nil,
keywords: nil,
creationDate: Date(),
lastUpdate: Date(),
pages: pdfPages
)
// Initialize OCR
val ocrProcessor = OcrProcessor(
context,
OcrConfiguration(listOf("en-US", "fr-FR"))
)
// Create PDF pages with OCR
val pdfPages = processedImages.map { (imageFile, pageSize) ->
// Run OCR
val ocrResult = ocrProcessor.processImage(imageFile)
// Create page with text layout
PDFPage(
imageFile = imageFile,
inchesSize = pageSize,
textLayout = ocrResult.textLayout // Makes PDF searchable
)
}
// Generate searchable PDF
val document = PDFDocument(
pages = pdfPages,
title = "Searchable Document",
password = null,
keywords = null
)
import GeniusScan from '@thegrizzlylabs/capacitor-plugin-genius-scan';
// Capture pages and OCR layout without generating the PDF automatically
const scanResult = await GeniusScan.scanWithConfiguration({
source: 'camera',
multiPage: true,
multiPageFormat: 'none',
ocrConfiguration: {
languages: ['en-US']
}
});
// Create PDF pages with OCR
const document = {
pages: scanResult.scans.map(scan => ({
imageUrl: scan.enhancedUrl,
hocrTextLayout: scan.ocrResult?.hocrTextLayout
}))
};
// Generate searchable PDF
await GeniusScan.generateDocument(
document,
{ outputFileUrl: 'file:///path/to/searchable_document.pdf' }
);
Control the page size in your generated PDF:
// Predefined sizes
let a4Page = GSKPDFPage(
filePath: imagePath,
inchesSize: GSKPDFSize(width: 8.27, height: 11.7),
textLayout: nil
)
let letterPage = GSKPDFPage(
filePath: imagePath,
inchesSize: GSKPDFSize(width: 8.5, height: 11.0),
textLayout: nil
)
// Custom size in inches
let customPage = GSKPDFPage(
filePath: imagePath,
inchesSize: GSKPDFSize(width: 8.5, height: 14.0),
textLayout: nil
)
// Fit to image dimensions
let fitPage = GSKPDFPage(
filePath: imagePath,
inchesSize: GSKPDFSize(width: 8.27, height: 0), // Maintains original image aspect ratio
textLayout: nil
)
// Predefined sizes
val a4Page = PDFPage(
File(imagePath),
PDFSize(width = 8.27, height = 11.7)
)
val letterPage = PDFPage(
File(imagePath),
PDFSize(width = 8.5, height = 11.0)
)
// Custom size in inches
val customPage = PDFPage(
File(imagePath),
PDFSize(width = 8.5, height = 14.0)
)
// Fit to image dimensions
val fitPage = PDFPage(
File(imagePath),
PDFSize(width = 8.27, height = 0.0) // Maintains original image aspect ratio
)
Process multiple documents and create separate PDFs:
func processBatch(scanResults: [GSKScanFlowScan]) {
// 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,
creationDate: Date(),
lastUpdate: Date(),
pages: pdfPages
)
Add searchable metadata to your PDFs:
let document = GSKPDFDocument(
title: "Invoice #12345",
password: nil,
keywords: "invoice, 2024, accounting, \(customerName)",
creationDate: Date(),
lastUpdate: Date(),
pages: pdfPages
)
Start with a free trial license to test the SDK, or contact us directly for a custom quote tailored to your needs.
© 2026 The Grizzly Labs. All rights reserved.