版本记录
版本号 | 时间 |
---|---|
V1.0 | 2019.02.01 星期五 |
前言
Firebase是一家实时后端数据库创业公司,它能帮助开发者很快的写出Web端和移动端的应用。自2014年10月Google收购Firebase以来,用户可以在更方便地使用Firebase的同时,结合Google的云服务。Firebase能让你的App从零到一。也就是说它可以帮助手机以及网页应用的开发者轻松构建App。通过Firebase背后负载的框架就可以简单地开发一个App,无需服务器以及基础设施。接下来几篇我们就一起看一下基于Firebase平台的开发。感兴趣的看下面几篇文章。
1. 基于Firebase平台开发(一) —— 基于ML Kit的iOS图片中文字的识别(一)
源码
1. Swift
首先看下代码组织结构
看下sb中的内容
下面就是源码了
1. AppDelegate.swift
import UIKit
import Firebase
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
override init() {
FirebaseApp.configure()
}
}
2. ViewController.swift
import UIKit
import MobileCoreServices
class ViewController: UIViewController {
@IBOutlet weak var imageView: UIImageView!
@IBOutlet weak var textView: UITextView!
@IBOutlet weak var cameraButton: UIButton!
let processor = ScaledElementProcessor()
var frameSublayer = CALayer()
var scannedText: String = "Detected text can be edited here." {
didSet {
textView.text = scannedText
}
}
override func viewDidLoad() {
super.viewDidLoad()
// Notifications to slide the keyboard up
NotificationCenter.default.addObserver(self, selector: #selector(ViewController.keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(ViewController.keyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil)
imageView.layer.addSublayer(frameSublayer)
drawFeatures(in: imageView)
}
// MARK: Touch handling to dismiss keyboard
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
if let evt = event, let tchs = evt.touches(for: view), tchs.count > 0 {
textView.resignFirstResponder()
}
}
// MARK: Actions
@IBAction func cameraDidTouch(_ sender: UIButton) {
if UIImagePickerController.isSourceTypeAvailable(.camera) {
presentImagePickerController(withSourceType: .camera)
} else {
let alert = UIAlertController(title: "Camera Not Available", message: "A camera is not available. Please try picking an image from the image library instead.", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
present(alert, animated: true, completion: nil)
}
}
@IBAction func libraryDidTouch(_ sender: UIButton) {
presentImagePickerController(withSourceType: .photoLibrary)
}
@IBAction func shareDidTouch(_ sender: UIBarButtonItem) {
let vc = UIActivityViewController(activityItems: [scannedText, imageView.image!], applicationActivities: [])
present(vc, animated: true, completion: nil)
}
// MARK: Keyboard slide up
@objc func keyboardWillShow(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
if view.frame.origin.y == 0 {
view.frame.origin.y -= keyboardSize.height
}
}
}
@objc func keyboardWillHide(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
if view.frame.origin.y != 0 {
view.frame.origin.y += keyboardSize.height
}
}
}
private func removeFrames() {
guard let sublayers = frameSublayer.sublayers else { return }
for sublayer in sublayers {
sublayer.removeFromSuperlayer()
}
}
// 1
private func drawFeatures(in imageView: UIImageView, completion: (() -> Void)? = nil) {
removeFrames()
processor.process(in: imageView) { text, elements in
elements.forEach() { element in
self.frameSublayer.addSublayer(element.shapeLayer)
}
self.scannedText = text
completion?()
}
}
}
extension ViewController: UIImagePickerControllerDelegate, UINavigationControllerDelegate, UIPopoverPresentationControllerDelegate {
// MARK: UIImagePickerController
private func presentImagePickerController(withSourceType sourceType: UIImagePickerController.SourceType) {
let controller = UIImagePickerController()
controller.delegate = self
controller.sourceType = sourceType
controller.mediaTypes = [String(kUTTypeImage), String(kUTTypeMovie)]
present(controller, animated: true, completion: nil)
}
// MARK: UIImagePickerController Delegate
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]) {
if let pickedImage =
info[UIImagePickerController.InfoKey.originalImage] as? UIImage {
imageView.contentMode = .scaleAspectFit
let fixedImage = pickedImage.fixOrientation()
imageView.image = fixedImage
drawFeatures(in: imageView)
}
dismiss(animated: true, completion: nil)
}
}
3. +UIImage.swift
import UIKit
extension UIImage {
// Thx to: https://stackoverflow.com/questions/8915630/ios-uiimageview-how-to-handle-uiimage-image-orientation
func fixOrientation() -> UIImage? {
guard let cgImage = cgImage else {
return nil
}
if imageOrientation == .up {
return self
}
let width = self.size.width
let height = self.size.height
var transform = CGAffineTransform.identity
switch imageOrientation {
case .down, .downMirrored:
transform = transform.translatedBy(x: width, y: height)
transform = transform.rotated(by: CGFloat.pi)
case .left, .leftMirrored:
transform = transform.translatedBy(x: width, y: 0)
transform = transform.rotated(by: 0.5*CGFloat.pi)
case .right, .rightMirrored:
transform = transform.translatedBy(x: 0, y: height)
transform = transform.rotated(by: -0.5*CGFloat.pi)
case .up, .upMirrored:
break
}
// Now we draw the underlying CGImage into a new context, applying the transform
// calculated above.
guard let colorSpace = cgImage.colorSpace else {
return nil
}
guard let context = CGContext(
data: nil,
width: Int(width),
height: Int(height),
bitsPerComponent: cgImage.bitsPerComponent,
bytesPerRow: 0,
space: colorSpace,
bitmapInfo: UInt32(cgImage.bitmapInfo.rawValue)
) else {
return nil
}
context.concatenate(transform);
switch imageOrientation {
case .left, .leftMirrored, .right, .rightMirrored:
// Grr...
context.draw(cgImage, in: CGRect(x: 0, y: 0, width: height, height: width))
default:
context.draw(cgImage, in: CGRect(x: 0, y: 0, width: width, height: height))
}
// And now we just create a new UIImage from the drawing context
guard let newCGImg = context.makeImage() else {
return nil
}
let img = UIImage(cgImage: newCGImg)
return img;
}
}
4. ScaledElementProcessor.swift
import Firebase
struct ScaledElement {
let frame: CGRect
let shapeLayer: CALayer
}
class ScaledElementProcessor {
let vision = Vision.vision()
var textRecognizer: VisionTextRecognizer!
init() {
textRecognizer = vision.onDeviceTextRecognizer()
}
func process(in imageView: UIImageView, callback: @escaping (_ text: String, _ scaledElements: [ScaledElement]) -> Void) {
guard let image = imageView.image else { return }
let visionImage = VisionImage(image: image)
textRecognizer.process(visionImage) { result, error in
guard error == nil, let result = result, !result.text.isEmpty else {
callback("", [])
return
}
var scaledElements: [ScaledElement] = []
for block in result.blocks {
for line in block.lines {
for element in line.elements {
let frame = self.createScaledFrame(featureFrame: element.frame, imageSize: image.size, viewFrame: imageView.frame)
let shapeLayer = self.createShapeLayer(frame: frame)
let scaledElement = ScaledElement(frame: frame, shapeLayer: shapeLayer)
scaledElements.append(scaledElement)
}
}
}
callback(result.text, scaledElements)
}
}
private func createShapeLayer(frame: CGRect) -> CAShapeLayer {
let bpath = UIBezierPath(rect: frame)
let shapeLayer = CAShapeLayer()
shapeLayer.path = bpath.cgPath
shapeLayer.strokeColor = Constants.lineColor
shapeLayer.fillColor = Constants.fillColor
shapeLayer.lineWidth = Constants.lineWidth
return shapeLayer
}
private func createScaledFrame(featureFrame: CGRect, imageSize: CGSize, viewFrame: CGRect) -> CGRect {
let viewSize = viewFrame.size
let resolutionView = viewSize.width / viewSize.height
let resolutionImage = imageSize.width / imageSize.height
var scale: CGFloat
if resolutionView > resolutionImage {
scale = viewSize.height / imageSize.height
} else {
scale = viewSize.width / imageSize.width
}
let featureWidthScaled = featureFrame.size.width * scale
let featureHeightScaled = featureFrame.size.height * scale
let imageWidthScaled = imageSize.width * scale
let imageHeightScaled = imageSize.height * scale
let imagePointXScaled = (viewSize.width - imageWidthScaled) / 2
let imagePointYScaled = (viewSize.height - imageHeightScaled) / 2
let featurePointXScaled = imagePointXScaled + featureFrame.origin.x * scale
let featurePointYScaled = imagePointYScaled + featureFrame.origin.y * scale
return CGRect(x: featurePointXScaled, y: featurePointYScaled, width: featureWidthScaled, height: featureHeightScaled)
}
// MARK: - private
private enum Constants {
static let lineWidth: CGFloat = 3.0
static let lineColor = UIColor.yellow.cgColor
static let fillColor = UIColor.clear.cgColor
}
}
后记
本篇主要讲述了基于ML Kit的iOS图片中文字的识别,感兴趣的给个赞或者关注~~~