文档章节

如何在Mac上使用Swift调用C接口开发条形码应用

yushulx
 yushulx
发布于 2015/08/25 11:01
字数 953
阅读 248
收藏 3

虽然Objective-C还活的很好,但是苹果已经把重心转移到Swift上。未来Mac和iOS的开发必然是以Swift为主。因为Swift还比较新,很多SDK还没有提供Swift版本。这里分享下如何使用Swift来调用C。

参考原文:How to Bridge C Code to Create Swift Barcode Reader on Mac

作者:Xiao Ling

翻译:yushulx

软件下载

混合使用Swift和C

苹果在iBooks里提供了电子书Using Swift with Cocoa and Objective-C。在网页上可以阅读Interacting with C APIs

Swift和C类型映射关系参考:

使用Swift和C在Mac上实现1D/2D条形码应用

在Xcode中使用快捷键Command+Shift+N创建新工程。

头文件和依赖的库直接拖入工程就行了。Xcode会自动关联。

Command+N创建一个C文件,用于调用底层的C动态链接库(Dynamsoft Barcode dylib)。

完成之后,Xcode会弹出提示:

确认之后,Xcode会自动生成一个桥接头文件。把C用到的头文件添加进去:

#import "native_lib.h"

参考Dynamsoft Barcode SDK的在线代码示例做一些修改:

#include "native_lib.h"
 
int dbr_release_memory(pBarcodeResultArray paryResult)
{
    DBR_FreeBarcodeResults(&paryResult);
    printf("Game Over\n");
    return 0;
}
 
pBarcodeResultArray dbr_decodeBarcodeFile(char* pszImageFile)
{
    // Parse command
    __int64 llFormat = (OneD |QR_CODE);
 
    int iMaxCount = 0x7FFFFFFF;
    int iIndex = 0;
    ReaderOptions ro = {0};
    pBarcodeResultArray paryResult = NULL;
    int iRet = -1;
    char * pszTemp = NULL;
    char * pszTemp1 = NULL;
    struct timeval begin, end;
 
    if (NULL == pszImageFile)
    {
        printf("The syntax of the command is incorrect.\n");
        return NULL;
    }
 
    // Set license
    DBR_InitLicense("A825E753D10C6CAC7C661140EC5ABEC3");
 
    // Read barcode
    gettimeofday(&begin, NULL);
    ro.llBarcodeFormat = llFormat;
    ro.iMaxBarcodesNumPerPage = iMaxCount;
    iRet = DBR_DecodeFile(pszImageFile, &ro, &paryResult);
    gettimeofday(&end, NULL);
 
    // Output barcode result
    pszTemp = (char*)malloc(4096);
    if (iRet != DBR_OK)
    {
        sprintf(pszTemp, "Failed to read barcode: %s\r\n", DBR_GetErrorString(iRet));
        printf("%s", pszTemp);
        free(pszTemp);
        return NULL;
    }
 
    if (paryResult->iBarcodeCount == 0)
    {
        sprintf(pszTemp, "No barcode found. Total time spent: %.3f seconds.\r\n",
                ((float)((end.tv_sec * 1000 * 1000 +  end.tv_usec) - (begin.tv_sec * 1000 * 1000 + begin.tv_usec))/(1000 * 1000)));
        printf("%s", pszTemp);
        DBR_FreeBarcodeResults(&paryResult);
        return 0;
    }
 
    sprintf(pszTemp, "Total barcode(s) found: %d. Total time spent: %.3f seconds\r\n\r\n", paryResult->iBarcodeCount,
            ((float)((end.tv_sec * 1000 * 1000 +  end.tv_usec) - (begin.tv_sec * 1000 * 1000 + begin.tv_usec))/(1000 * 1000)));
    printf("%s", pszTemp);
 
    return paryResult;
}

修改下生成的头文件:

#ifndef __DBRConsole__native_lib__
#define __DBRConsole__native_lib__
 
#include <stdio.h>
 
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
 
#include "If_DBR.h"
 
pBarcodeResultArray dbr_decodeBarcodeFile(char* fileName);
int dbr_release_memory(pBarcodeResultArray paryResult);
const char * GetFormatStr(__int64 format);
 
#endif /* defined(__DBRConsole__native_lib__) */

用Swift编写命令行工具

把Swift中的String转换成char *:

var file: String = "/Applications/Dynamsoft/Barcode Reader 3.0 Trial/Images/AllSupportedBarcodeTypes.tif" // barcode file
//let namePtr = strdup(filePath.bridgeToObjectiveC().UTF8String)
 
var filePtr = strdup(file.cStringUsingEncoding(NSUTF8StringEncoding)!)
var fileName: UnsafeMutablePointer<CChar> = UnsafeMutablePointer(filePtr)

注释掉的接口bridgeToObjectiveC 在早期的Swift版本中是可以用的。Xcode 6.4中已经去掉了。

命令行获取Barcode结果:

var result : pBarcodeResultArray = dbr_decodeBarcodeFile(fileName)
 
free(filePtr)
 
println("Total barcode: \(String(result.move().iBarcodeCount))\n.......")
 
var count = result.move().iBarcodeCount
var pBarcodeResult: pBarcodeResult = nil
var barcodeIndex = 1
 
// print barcode recognition results
for i in 0..<Int(count) {
    pBarcodeResult = result.move().ppBarcodes.advancedBy(i).move()
    println("Barcode: \(barcodeIndex++)")
    println("Page: \(String(pBarcodeResult.move().iPageNum))")
    var lFormat: __int64 = pBarcodeResult.move().llFormat
    var format = String.fromCString(GetFormatStr(lFormat))
    println("Type: \(format!)")
    println("Value: \(String.fromCString(pBarcodeResult.move().pBarcodeData)!)")
    println(".......")
 
}
 
// free C memory
dbr_release_memory(result)

用Swift创建Cocoa应用

AppDelegate.swift中创建按钮和文本控件:

@IBOutlet weak var window: NSWindow!
@IBOutlet weak var btLoad: NSButton!
@IBOutlet weak var btRead: NSButton!
@IBOutlet weak var text: NSTextField!
@IBOutlet weak var filePath: NSTextField!

创建按钮响应函数:

@IBAction func onClick(sender: NSButton) {
        var title = sender.title
        switch(title) {
        case "Load Barcode File":
            dispatch_async(dispatch_get_main_queue()) {
                self.openPanel()
            }
            break
        case "Read Barcode":
 
            if self.filePath.stringValue == "" {
                text.stringValue = "Please add image path!"
                return
            }
 
            println("default:" + self.filePath.stringValue)
            var dbr = DBR()
            text.stringValue = dbr.decodeFile(self.filePath.stringValue)!
            break
        default:
            break
        }
 
    }

在Interface Builder中把代码和UI元素关联起来:

使用NSOpenPanel 加载文件:

func openPanel() {
        var openPanel = NSOpenPanel()
        openPanel.allowsMultipleSelection = false
        openPanel.canChooseDirectories = false
        openPanel.canCreateDirectories = false
        openPanel.canChooseFiles = true
        openPanel.beginWithCompletionHandler { (result) -> Void in
            if result == NSFileHandlingPanelOKButton {
                if let path = openPanel.URL?.path {
                    self.filePath.stringValue = path
                }
            }
        }
 
    }

创建DBR.swift用于读取条形码:

import Foundation
 
class DBR {
    func decodeFile(file: String)->String? {
 
        var filePtr = strdup(file.cStringUsingEncoding(NSUTF8StringEncoding)!)
        var fileName: UnsafeMutablePointer<CChar> = UnsafeMutablePointer(filePtr)
        var result : pBarcodeResultArray = dbr_decodeBarcodeFile(fileName)
 
        free(filePtr)
 
        println("Total barcode: \(String(result.move().iBarcodeCount))\n.......")
 
        var count = result.move().iBarcodeCount
        var barcodeIndex = 1
        var results: String = ""
        // print barcode recognition results
        for i in 0..<Int(count) {
            var pBarcodeResult = result.move().ppBarcodes.advancedBy(i).move()
 
            results += "Barcode: \(barcodeIndex++)\n"
            results += "Page: \(String(pBarcodeResult.move().iPageNum))\n"
 
            var lFormat: __int64 = pBarcodeResult.move().llFormat
            var format = String.fromCString(GetFormatStr(lFormat))
 
            results += "Type: \(format!)\n"
            results += "Value: \(String.fromCString(pBarcodeResult.move().pBarcodeData)!)\n"
            results += ".......\n"
 
        }
 
        // free C memory
        dbr_release_memory(result)
 
        return results
    }
}

运行1D/2D条形码应用:

源码

https://github.com/yushulx/swift-barcode-reader


© 著作权归作者所有

共有 人打赏支持
yushulx
粉丝 28
博文 104
码字总数 59573
作品 0
杭州
私信 提问
构建基于 Node.js 的条形码识别程序

在这篇文章中,我们将展示一个非常简单的方法构建一个自定义的 Node 模块,该模块封装了Dynamsoft Barcode Reader SDK ,支持 Windows、Linux 和 OS X,同时我们将演示如何集成这块模块实现一...

oschina
2016/02/12
3.6K
2
使用swift语言编写iOS应用

2014 WWDC,苹果推出了swift语言来作为新的苹果平台语言。该语言风格看起来像一个各种语言大杂烩,但作为苹果平台新推语言,受到了很多关注。作为一个JSer,感觉这个语言应该比OC更容易上手。...

Haffe
2014/06/04
0
4
Dynamsoft WebAssembly条形码SDK预览

WebAssembly(Wasm)是一种用于Web开发的革命性技术。 它让运行在Web浏览器中的前端应用拥有媲美原生应用的速度。使用WebAssembly,可以方便地把C / C ++代码移植到Web前端,通过JavaScript调...

yushulx
2018/07/17
0
0
idea4good/GuiLiteSamples

GuiLite Samples - 你自己的精彩 - 开发者qq群: 在IOS,Mac下的运行效果: 在Android,嵌入式ARM Linux下的运行效果: 在Windows混合现实下的运行效果: GuiLite samples包括2个跨平台工程,一个...

idea4good
2018/01/04
0
0
15个快速学习苹果Swift编程语言的入门教程

要说今年最火的编程语言是什么。那就非Swift莫属了。当然最主要还是市场炒的比较热,加上官方Swift教程《The Swift Programming Language》在北航的大三学生发起在github上进行协同翻译获得了...

欲思
2014/07/24
19.9K
7

没有更多内容

加载失败,请刷新页面

加载更多

Confluence 6 升级中的一些常见问题

升级的时候遇到了问题了吗? 如果你想尝试重新进行升级的话,你需要首先重新恢复老的备份。不要尝试再次对 Confluence 进行升级或者在升级失败后重新启动老的 Confluence。 在升级过程中的一...

honeymoose
今天
2
0
C++随笔(四)Nuget打包

首先把自己编译好的包全部准备到一个文件夹 像这样 接下来新建一个文本文档,后缀名叫.nuspec 填写内容 <?xml version="1.0"?><package xmlns="http://schemas.microsoft.com/packaging/201......

Pulsar-V
今天
2
0
再谈使用开源软件搭建数据分析平台

三年前,我写了这篇博客使用开源软件快速搭建数据分析平台, 当时收到了许多的反馈,有50个点赞和300+的收藏。到现在我还能收到一些关于dataplay2的问题。在过去的三年,开源社区和新技术的发...

naughty
今天
11
0
Python3的日期和时间

python 中处理日期时间数据通常使用datetime和time库 因为这两个库中的一些功能有些重复,所以,首先我们来比较一下这两个库的区别,这可以帮助我们在适当的情况下时候合适的库。 在Python文...

编程老陆
今天
2
0
分布式面试整理

并发和并行 并行是两个任务同时进行,而并发呢,则是一会做一个任务一会又切换做另一个任务。 临界区 临界区用来表示一种公共资源或者说是共享数据,可以被多个线程使用,但是每一次,只能有...

群星纪元
今天
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部