如何在Mac上用Ruby封装C/C++接口

最近在codecademy上学习了下Ruby,顺便分享下如何在Mac上用Ruby封装Dynamsoft C/C++ barcode API 。

参考原文:How to Make Ruby Barcode Reader with C++ Barcode SDK on Mac OS X

作者:Xiao Ling

翻译:yushulx

下载SDK

http://www.dynamsoft.com/Downloads/Dynamic-Barcode-Reader-Download.aspx

创建Ruby Barcode工程

创建extconf.rb

require 'mkmf'
 
extension_name = 'dynamsoftbarcode'
 
dir_config(extension_name)
 
create_makefile(extension_name)

自动生成Makefile:

ruby extconf .rb

打开Makefile,修改配置。

  • 添加头文件路径

    dbrdir = /Applications/Dynamsoft/Barcode\ Reader\ 3.0\ Trial/Include
     
    INCFLAGS = -I. -I$(arch_hdrdir) -I$(hdrdir)/ruby/backward -I$(hdrdir) -I$(srcdir) -I$(dbrdir)
  • 添加库路径

    LIBS = $(LIBRUBYARG_SHARED) -lpthread -ldl -lobjc -lDynamsoftBarcodeReader

打开dynamsoftbarcode.c,添加入口和方法:

VALUE BarcodeReader = Qnil;
 
void Init_dynamsoftbarcode();
 
VALUE method_decodeFile(VALUE self, VALUE path);
 
void Init_dynamsoftbarcode() {
    BarcodeReader = rb_define_module("BarcodeReader");
    rb_define_method(BarcodeReader, "decodeFile", method_decodeFile, 1);
}
 
VALUE method_decodeFile(VALUE self, VALUE path) {
    char *pszPath = StringValueCStr(path);
    VALUE ary = decode(pszPath);
    return ary;
}

使用Dynamsoft Barcode SDK提供的代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <If_DBR.h>
 
#define strcmpi(dst, src) strcasecmp(dst, src)
 
__int64 GetFormat(const char * pstr)
{
    __int64 llFormat = 0;
    const char * pszFormat = pstr;
 
    if (strcasestr(pszFormat, "code_39") != NULL)
        llFormat |= CODE_39;
    if (strcasestr(pszFormat, "code_128") != NULL)
        llFormat |= CODE_128;
    if (strcasestr(pszFormat, "code_93") != NULL)
        llFormat |= CODE_93;
    if (strcasestr(pszFormat, "codabar") != NULL)
        llFormat |= CODABAR;
    if (strcasestr(pszFormat, "itf") != NULL)
        llFormat |= ITF;
    if (strcasestr(pszFormat, "upc_a") != NULL)
        llFormat |= UPC_A;
    if (strcasestr(pszFormat, "upc_e") != NULL)
        llFormat |= UPC_E;
    if (strcasestr(pszFormat, "ean_13") != NULL)
        llFormat |= EAN_13;
    if (strcasestr(pszFormat, "ean_8") != NULL)
        llFormat |= EAN_8;
    if (strcasestr(pszFormat, "industrial_25") != NULL)
        llFormat |= INDUSTRIAL_25;
    if (strcasestr(pszFormat, "oned") != NULL)
        llFormat = OneD;
    if (strcasestr(pszFormat, "qr_code") != NULL)
        llFormat |= QR_CODE;
 
    return llFormat;
}
 
const char * GetFormatStr(__int64 format)
{
    if (format == CODE_39)
        return "CODE_39";
    if (format == CODE_128)
        return "CODE_128";
    if (format == CODE_93)
        return "CODE_93";
    if (format == CODABAR)
        return "CODABAR";
    if (format == ITF)
        return "ITF";
    if (format == UPC_A)
        return "UPC_A";
    if (format == UPC_E)
        return "UPC_E";
    if (format == EAN_13)
        return "EAN_13";
    if (format == EAN_8)
        return "EAN_8";
    if (format == INDUSTRIAL_25)
        return "INDUSTRIAL_25";
    if (format == QR_CODE)
        return "QR_CODE";
 
    return "UNKNOWN";
}
 
int decode(const char *pszImageFile)
{
    __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 1;
    }
 
    // Set license
    DBR_InitLicense("B8DF4560D0953299D5454C71A38D1FEB");
 
    // 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 1;
    }
 
    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);
    for (iIndex = 0; iIndex < paryResult->iBarcodeCount; iIndex++)
    {
        sprintf(pszTemp, "Barcode %d:\r\n", iIndex + 1);
        // printf("%s", pszTemp);
        sprintf(pszTemp, "%s    Page: %d\r\n", pszTemp, paryResult->ppBarcodes[iIndex]->iPageNum);
        // printf("%s", pszTemp);
        sprintf(pszTemp, "%s    Type: %s\r\n", pszTemp, GetFormatStr(paryResult->ppBarcodes[iIndex]->llFormat));
        // printf("%s", pszTemp);
        pszTemp1 = (char*)malloc(paryResult->ppBarcodes[iIndex]->iBarcodeDataLength + 1);
        memset(pszTemp1, 0, paryResult->ppBarcodes[iIndex]->iBarcodeDataLength + 1);
        memcpy(pszTemp1, paryResult->ppBarcodes[iIndex]->pBarcodeData, paryResult->ppBarcodes[iIndex]->iBarcodeDataLength);
        sprintf(pszTemp, "%s    Value: %s\r\n", pszTemp, pszTemp1);
        // printf("%s", pszTemp);
        free(pszTemp1);
    }
 
    free(pszTemp);
    DBR_FreeBarcodeResults(&paryResult);
 
    return iRet;
}

C String转换成 VALUE(VALUE表示Ruby对象)

VALUE ary = rb_ary_new();
rb_ary_push(ary, rb_str_new_cstr(pszTemp));

创建Ruby脚本barcode_reader.rb调用接口:

require 'dynamsoftbarcode'
include BarcodeReader
 
if ARGV.length == 0
  puts "Please add a barcode file path!"
else
  $filePath = ARGV[0]
  $results = decodeFile($filePath)
  $results.each do |i|
     puts "#{i}"
  end
 
  puts "Game Over!"
end

执行make。如果看到下面的警告:

ld: warning: directory not found for option '-L/usr/local/lib'

打开Makefile ,把

ldflags = -L. -L/usr/local/lib

改成

ldflags = -L. -L/usr/lib.

再make一次就好了:

linking shared-object dynamsoftbarcode.bundle

运行sudo make install安装。

执行脚本测试:

ruby barcode_reader.rb barcode_file

截图:

如何在Mac上用Ruby封装C/C++接口_第1张图片

参考

  • http://docs.ruby-lang.org/en/2.1.0/README_EXT.html

  • https://silverhammermba.github.io/emberb/c/

源码

https://github.com/dynamsoftsamples/ruby-barcode-reader



你可能感兴趣的:(C++,Ruby,sdk,extension,barcode)