ikromjon/nativephp-mobile-document-scanner

Document scanner plugin for NativePHP Mobile - scan documents with edge detection, cropping, and perspective correction using native camera APIs

Maintainers

Package info

github.com/Ikromjon1998/nativephp-mobile-document-scanner

Type:nativephp-plugin

pkg:composer/ikromjon/nativephp-mobile-document-scanner

Statistics

Installs: 0

Dependents: 0

Suggesters: 0

Stars: 4

Open Issues: 0

v1.3.0 2026-04-09 17:02 UTC

README

Tests Total Downloads License: MIT PHP Version

Scan documents with automatic edge detection, perspective correction, and cropping in your NativePHP Mobile app — powered by native platform APIs.

Quick Start

composer require ikromjon/nativephp-mobile-document-scanner
php artisan native:plugin:register ikromjon/nativephp-mobile-document-scanner
php artisan native:run android  # or ios
use Ikromjon\DocumentScanner\Facades\DocumentScanner;
use Ikromjon\DocumentScanner\Events\DocumentScanned;
use Native\Mobile\Attributes\OnNative;

// In your Livewire component:
DocumentScanner::scan();

// Handle the result (Livewire method)
#[OnNative(DocumentScanned::class)]
public function onScanned($data)
{
    $paths = $data['paths'];           // ['/path/scan_0.jpg', ...]
    $pageCount = $data['pageCount'];   // 2
}

That's it. The scanner opens, the user scans, and you get the file paths back via events. See below for full options and JavaScript usage.

How It Works

Platform Native API Features
iOS VisionKit (VNDocumentCameraViewController) Auto edge detection, perspective correction, shadow removal, multi-page
Android Google ML Kit Document Scanner Auto edge detection, cropping, rotation, multi-page, gallery import

No external API keys or internet required. Camera permission is handled automatically.

Installation

composer require ikromjon/nativephp-mobile-document-scanner
php artisan native:plugin:register ikromjon/nativephp-mobile-document-scanner

Build your app (plugin requires a native build):

php artisan native:run android
# or
php artisan native:run ios

Note: The scanner requires a native build on a real device — it won't work with php artisan serve. If you call scan() without a native build, you'll see a warning in your Laravel log.

Configuration

Optionally publish the config file:

php artisan vendor:publish --tag=document-scanner-config
Key Default Description
default_max_pages 0 Default max pages per scan (0 = unlimited)
max_pages_limit 100 Absolute cap on pages per scan
default_output_format jpeg Default output format (jpeg or pdf)
default_jpeg_quality 90 Default JPEG compression quality (1-100)
storage_directory scanned-documents Subdirectory for scanned files
default_gallery_import false Allow gallery import (Android only)
default_scanner_mode full Scanner mode: base, filter, full (Android only)

Usage (PHP)

Scan a Document

use Ikromjon\DocumentScanner\Facades\DocumentScanner;

// Scan with defaults
DocumentScanner::scan();

// Scan with options
DocumentScanner::scan([
    'maxPages' => 3,
    'outputFormat' => 'jpeg',
    'jpegQuality' => 85,
]);

// Scan a single page (e.g. ID card)
DocumentScanner::scan(['maxPages' => 1]);

// Scan to PDF
DocumentScanner::scan(['outputFormat' => 'pdf']);

The scan() method opens the native scanner UI and returns immediately. Results are delivered asynchronously via events.

Type-Safe DTO

use Ikromjon\DocumentScanner\Data\ScanOptions;
use Ikromjon\DocumentScanner\Enums\OutputFormat;

DocumentScanner::scan(new ScanOptions(
    maxPages: 5,
    outputFormat: OutputFormat::Pdf,
));

Scan Parameters

Parameter Type Platform Description
maxPages int Both Max pages to scan (0 = unlimited)
outputFormat OutputFormat|string Both jpeg or pdf
jpegQuality int Both JPEG quality 1-100 (only for jpeg output)
galleryImport bool Android only Allow importing from device gallery
scannerMode ScannerMode|string Android only base, filter, or full

Full Livewire Example

A complete component that scans documents and displays the results:

use Livewire\Component;
use Native\Mobile\Attributes\OnNative;
use Ikromjon\DocumentScanner\Facades\DocumentScanner;
use Ikromjon\DocumentScanner\Events\DocumentScanned;
use Ikromjon\DocumentScanner\Events\ScanCancelled;
use Ikromjon\DocumentScanner\Events\ScanFailed;

class DocumentScannerComponent extends Component
{
    public array $scannedFiles = [];
    public string $error = '';

    public function scan()
    {
        DocumentScanner::scan(['maxPages' => 5]);
    }

    #[OnNative(DocumentScanned::class)]
    public function onScanned($data)
    {
        $this->scannedFiles = $data['paths'];
    }

    #[OnNative(ScanCancelled::class)]
    public function onCancelled()
    {
        // User dismissed the scanner
    }

    #[OnNative(ScanFailed::class)]
    public function onFailed($data)
    {
        $this->error = $data['error'];
    }
}

Important: Use #[OnNative(...)] (not #[On(...)]) for NativePHP events.

Listening to Events (Laravel)

use Ikromjon\DocumentScanner\Events\DocumentScanned;

class HandleDocumentScanned
{
    public function handle(DocumentScanned $event): void
    {
        // $event->paths — array of file paths
        // $event->pageCount — number of pages scanned
        // $event->outputFormat — 'jpeg' or 'pdf'
    }
}

Usage (JavaScript)

import {
  scan,
  imagesToPdf,
  pdfToImages,
  Events,
} from "../../vendor/ikromjon/nativephp-mobile-document-scanner/resources/js/index.js";
import { On } from "#nativephp";

// Open scanner
await scan({ maxPages: 3, outputFormat: "jpeg", jpegQuality: 90 });

// Listen for results
On(Events.DocumentScanned, (payload) => {
  console.log("Scanned:", payload.paths, payload.pageCount);
});

On(Events.ScanCancelled, () => {
  console.log("Cancelled");
});

On(Events.ScanFailed, (payload) => {
  console.error("Failed:", payload.error);
});

// Combine images into PDF
const result = await imagesToPdf(["/path/scan_0.jpg", "/path/scan_1.jpg"]);
console.log("PDF:", result.path);

// Extract thumbnails from PDF
const thumbs = await pdfToImages("/path/scan.pdf", 80);
console.log("Pages:", thumbs.paths);

Events

Event Payload When
DocumentScanned paths, pageCount, outputFormat Scanning completed successfully
ScanCancelled User cancelled the scanner
ScanFailed error An error occurred
PdfCreated path imagesToPdf() completed

Scanned Files

Scanned files are saved to the app's internal storage under the configured storage_directory (default: scanned-documents). File paths returned in the DocumentScanned event are absolute paths on the device.

  • JPEG output: one file per page (e.g. scan_0.jpg, scan_1.jpg)
  • PDF output: a single multi-page PDF file
  • Files persist until the app is uninstalled or you delete them manually

Which format to use?

JPEG (default) is the better choice for most apps. You get individual files per page, which means you can show page previews, let users view/delete specific pages, and convert to PDF later on your own terms (e.g. with fpdf). You also control file size via jpegQuality.

PDF is useful when you need a single file immediately and don't need to display or manipulate individual pages. Note that the native scanner produces the PDF directly — you can't extract page previews from it without a separate library.

See Smart Docs for an example that scans as JPEG by default and converts to PDF on demand.

Required Permissions

Android: CAMERA — declared automatically via nativephp.json. ML Kit handles the scanner UI internally.

iOS: VisionKit requests camera access at runtime. Your app's Info.plist must include an NSCameraUsageDescription string — NativePHP sets a default, but you should customize it for your app store submission (e.g. "This app uses the camera to scan documents").

No API keys or internet required.

Demo App

See Smart Docs — a full NativePHP mobile app that uses this plugin for document scanning.

Documentation

JPEG-to-PDF Conversion

Combine scanned JPEG pages into a single PDF on-device — no extra PHP library needed:

use Ikromjon\DocumentScanner\Facades\DocumentScanner;
use Ikromjon\DocumentScanner\Events\PdfCreated;
use Native\Mobile\Attributes\OnNative;

// Combine images into a PDF
$result = DocumentScanner::imagesToPdf([
    '/path/scan_0.jpg',
    '/path/scan_1.jpg',
]);
$pdfPath = $result['path']; // '/path/combined_1712345678.pdf'

// Listen for completion
#[OnNative(PdfCreated::class)]
public function onPdfCreated($data)
{
    $pdfPath = $data['path'];
}

Works with any JPEG files, not just scanned documents.

PDF Page Thumbnails

Extract page previews from a PDF — useful when you scan as PDF but need page-level previews:

$result = DocumentScanner::pdfToImages('/path/scan.pdf', quality: 80);
$pagePaths = $result['paths']; // ['/path/page_0.jpg', '/path/page_1.jpg']

Planned Features

  • File management — list, delete, and clean up scanned files via the plugin API
  • Image post-processing — grayscale, contrast, rotation on scanned images

See ROADMAP.md for full details and status.

Testing

composer test
composer analyse

Requirements

  • PHP 8.3+
  • NativePHP Mobile v3+
  • iOS 13+ / Android API 21+

License

MIT