Skip to content

Commit

Permalink
Merge pull request #5 from hansemannn/feature/swift
Browse files Browse the repository at this point in the history
feat: move to Swift, extend "pdfFromAllPages" API
  • Loading branch information
hansemannn authored Nov 14, 2021
2 parents 6f0a44e + 3d806bc commit 6d4050f
Show file tree
Hide file tree
Showing 12 changed files with 547 additions and 449 deletions.
17 changes: 17 additions & 0 deletions Classes/TiScanner.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
//
// TiScanner.h
// titanium-scanner
//
// Created by Your Name
// Copyright (c) 2021 Your Company. All rights reserved.
//

#import <UIKit/UIKit.h>

//! Project version number for TiScanner.
FOUNDATION_EXPORT double TiScannerVersionNumber;

//! Project version string for TiScanner.
FOUNDATION_EXPORT const unsigned char TiScannerVersionString[];

#import "TiScannerModuleAssets.h"
27 changes: 0 additions & 27 deletions Classes/TiScannerModule.h

This file was deleted.

129 changes: 0 additions & 129 deletions Classes/TiScannerModule.m

This file was deleted.

175 changes: 175 additions & 0 deletions Classes/TiScannerModule.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
//
// TiScannerModule.swift
// titanium-scanner
//
// Created by Your Name
// Copyright (c) 2021 Your Company. All rights reserved.
//

import UIKit
import TitaniumKit
import Vision
import VisionKit
import PDFKit

@objc(TiScannerModule)
class TiScannerModule: TiModule {

lazy var scanner: VNDocumentCameraViewController? = {
let scannerViewController = VNDocumentCameraViewController()
scannerViewController.delegate = self

return scannerViewController
}()

var currentScan: VNDocumentCameraScan?

func moduleGUID() -> String {
return "fc40b436-6d90-4cf0-9627-f56e4321b30f"
}

override func moduleId() -> String! {
return "ti.scanner"
}

func dismissAndCleanup() {
scanner?.dismiss(animated: true, completion: nil)
scanner?.delegate = nil
scanner = nil
}

// MARK: Public APIs

@objc(isSupported:)
func isSupported(unused: [Any]?) -> Bool {
return VNDocumentCameraViewController.isSupported
}

@objc(showScanner:)
func showScanner(unused: [Any]?) {
if let scanner = scanner {
TiApp.controller().present(scanner, animated: true, completion: nil)
}
}

@objc(imageOfPageAtIndex:)
func imageOfPageAtIndex(args: [Any]) -> TiBlob? {
guard let index = args.first as? Int, let scan = currentScan else { return nil }

let image = scan.imageOfPage(at: index)
return TiBlob(image: image)
}

@objc(pdfOfPageAtIndex:)
func pdfOfPageAtIndex(args: [Any]) -> TiBlob? {
guard let index = args.first as? Int, let scan = currentScan else { return nil }

let image = scan.imageOfPage(at: index)
let pdfDocument = PDFDocument()

if let pdfPage = PDFPage(image: image) {
pdfDocument.insert(pdfPage, at: 0)
}

return TiBlob(data: pdfDocument.dataRepresentation(), mimetype: "application/pdf")
}

@objc(pdfOfAllPages:)
func pdfOfAllPages(args: [Any]?) -> TiBlob? {
guard let scan = currentScan else { return nil }

var resizeImages = false
var padding = 80

if let params = args?.first as? [String: Any] {
resizeImages = params["resizeImages"] as? Bool ?? false
padding = params["padding"] as? Int ?? 80
}

let pdfDocument = PDFDocument()

for index in 0...scan.pageCount - 1 {
let image = scan.imageOfPage(at: index)

if resizeImages {
// Get the raw data representation
if let pdfData = A4PDFDataFromCentered(image: image, with: Float(padding)) {
// Generate a PDF document from the raw data
if let pdfDataDocument = PDFDocument(data: pdfData) {
// Get the page from the generate document
if let pdfPage = pdfDataDocument.page(at: 0) {
// Add the generated page to the actual document
pdfDocument.insert(pdfPage, at: index)
}
}
}
} else {
if let pdfPage = PDFPage(image: image) {
pdfDocument.insert(pdfPage, at: index)
}
}
}

return TiBlob(data: pdfDocument.dataRepresentation(), mimetype: "application/pdf")
}
}

// MARK: VNDocumentCameraViewControllerDelegate

extension TiScannerModule: VNDocumentCameraViewControllerDelegate {
func documentCameraViewControllerDidCancel(_ controller: VNDocumentCameraViewController) {
fireEvent("cancel")
dismissAndCleanup()
}

func documentCameraViewController(_ controller: VNDocumentCameraViewController, didFailWithError error: Error) {
fireEvent("error", with: ["error": error.localizedDescription])
dismissAndCleanup()
}

func documentCameraViewController(_ controller: VNDocumentCameraViewController, didFinishWith scan: VNDocumentCameraScan) {
currentScan = scan

fireEvent("success", with: ["count": scan.pageCount, "title": scan.title])
dismissAndCleanup()
}
}

// MARK: Utils to generate a centered image

extension TiScannerModule {
func A4PDFDataFromCentered(image: UIImage, with padding: Float) -> Data? {
let A4_WIDTH: Float = 595.2
let A4_HEIGHT: Float = 841.8

// Prepare raw data
let pdfData = NSMutableData()
let pdfConsumer = CGDataConsumer(data: pdfData as CFMutableData)!

// Calculate the aspect ratio
let imageWidth = A4_WIDTH - (padding * 2)
let imageHeight = round(CGFloat(imageWidth) * (image.size.height / image.size.width))

// Calculate the bounces
var mediaBox = CGRect(x: 0,
y: 0,
width: CGFloat(A4_WIDTH),
height: CGFloat(A4_HEIGHT)); // A4

let imageBox = CGRect(x: CGFloat((A4_WIDTH / 2) - (imageWidth / 2)),
y: (CGFloat(A4_HEIGHT) / 2) - (imageHeight / 2),
width: CGFloat(imageWidth),
height: CGFloat(imageHeight))

// Create the context to draw in
let pdfContext = CGContext(consumer: pdfConsumer, mediaBox: &mediaBox, nil)!

// Perform the drawing
pdfContext.beginPage(mediaBox: &mediaBox)
pdfContext.draw(image.cgImage!, in: imageBox)
pdfContext.endPage()
pdfContext.closePDF()

return pdfData as Data
}
}
24 changes: 24 additions & 0 deletions Info.plist
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>NSPrincipalClass</key>
<string></string>
</dict>
</plist>
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ document.
- [x] `showScanner`
- [x] `imageOfPageAtIndex(index)` (after the `success` event)
- [x] `pdfOfPageAtIndex(index)` (after the `success` event)
- [x] `pdfOfAllPages()` (after the `success` event)
- [x] `pdfOfAllPages(params)` (after the `success` event - the params include `resizeImages` and `padding` to be used to generate resized A4 PDF's)

### Events

Expand Down
2 changes: 1 addition & 1 deletion TiScanner_Prefix.pch
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@

#ifdef __OBJC__
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#endif

Loading

0 comments on commit 6d4050f

Please sign in to comment.